pkgsign.c
1 /*- 2 * Copyright (c) 2021 Kyle Evans <kevans@FreeBSD.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer 9 * in this position and unchanged. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <assert.h> 27 #include <errno.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include "private/pkg.h" 32 #include "private/pkgsign.h" 33 #include "pkghash.h" 34 #include "xmalloc.h" 35 36 /* Other parts of libpkg should use pkgsign instead of rsa directly. */ 37 extern const struct pkgsign_ops pkgsign_ossl; 38 extern const struct pkgsign_ops pkgsign_ecc; 39 40 static pkghash *pkgsign_verifiers; 41 42 /* 43 * The eventual goal is to allow plugins to register their own pkgsign 44 * implementations as needed. The initial sketch was to add a constructor 45 * to register the builtin pkgsign implementations since there should only be 46 * a couple of them, but this is saved for later work. 47 */ 48 static struct pkgsign_impl { 49 const char *pi_name; 50 const struct pkgsign_ops *pi_ops; 51 int pi_refs; /* XXX */ 52 } pkgsign_builtins[] = { 53 { 54 .pi_name = "rsa", 55 .pi_ops = &pkgsign_ossl, 56 }, 57 { 58 .pi_name = "ecc", 59 .pi_ops = &pkgsign_ecc, 60 }, 61 { 62 .pi_name = "ecdsa", 63 .pi_ops = &pkgsign_ecc, 64 }, 65 { 66 .pi_name = "eddsa", 67 .pi_ops = &pkgsign_ecc, 68 }, 69 }; 70 71 static int 72 pkgsign_new(const char *name, struct pkgsign_ctx **ctx) 73 { 74 struct pkgsign_impl *impl; 75 const struct pkgsign_ops *ops; 76 struct pkgsign_ctx *nctx; 77 size_t ctx_size; 78 int ret; 79 80 assert(*ctx == NULL); 81 82 ops = NULL; 83 for (size_t i = 0; i < NELEM(pkgsign_builtins); i++) { 84 impl = &pkgsign_builtins[i]; 85 if (STREQ(name, impl->pi_name)) { 86 ops = impl->pi_ops; 87 break; 88 } 89 } 90 91 if (ops == NULL) 92 return (EPKG_FATAL); 93 94 ctx_size = ops->pkgsign_ctx_size; 95 assert(ctx_size == 0 || ctx_size >= sizeof(struct pkgsign_ctx)); 96 if (ctx_size == 0) 97 ctx_size = sizeof(struct pkgsign_ctx); 98 99 nctx = xcalloc(1, ctx_size); 100 nctx->impl = impl; 101 102 ret = EPKG_OK; 103 if (ops->pkgsign_new != NULL) 104 ret = (*ops->pkgsign_new)(name, nctx); 105 106 if (ret != EPKG_OK) { 107 free(nctx); 108 return (ret); 109 } 110 111 impl->pi_refs++; 112 *ctx = nctx; 113 return (EPKG_OK); 114 } 115 116 int 117 pkgsign_new_verify(const char *name, const struct pkgsign_ctx **octx) 118 { 119 struct pkgsign_ctx *ctx; 120 pkghash_entry *entry; 121 int ret; 122 123 entry = pkghash_get(pkgsign_verifiers, name); 124 if (entry != NULL) { 125 *octx = entry->value; 126 return (EPKG_OK); 127 } 128 129 ctx = NULL; 130 if ((ret = pkgsign_new(name, &ctx)) != EPKG_OK) 131 return (ret); 132 133 pkghash_safe_add(pkgsign_verifiers, name, ctx, NULL); 134 *octx = ctx; 135 return (EPKG_OK); 136 } 137 138 int 139 pkgsign_new_sign(const char *name, struct pkgsign_ctx **ctx) 140 { 141 142 return (pkgsign_new(name, ctx)); 143 } 144 145 void 146 pkgsign_set(struct pkgsign_ctx *sctx, pkg_password_cb *cb, const char *keyfile) 147 { 148 149 sctx->pw_cb = cb; 150 sctx->path = keyfile; 151 } 152 153 void 154 pkgsign_free(struct pkgsign_ctx *ctx) 155 { 156 struct pkgsign_impl *impl; 157 const struct pkgsign_ops *ops; 158 159 if (ctx == NULL) 160 return; 161 impl = ctx->impl; 162 ops = impl->pi_ops; 163 if (ops->pkgsign_free != NULL) 164 (*ops->pkgsign_free)(ctx); 165 166 impl->pi_refs--; 167 free(ctx); 168 } 169 170 int 171 pkgsign_sign(struct pkgsign_ctx *ctx, const char *path, unsigned char **sigret, 172 size_t *siglen) 173 { 174 175 return (*ctx->impl->pi_ops->pkgsign_sign)(ctx, path, sigret, siglen); 176 } 177 178 int 179 pkgsign_verify(const struct pkgsign_ctx *ctx, const char *key, 180 unsigned char *sig, size_t siglen, int fd) 181 { 182 183 return (*ctx->impl->pi_ops->pkgsign_verify)(ctx, key, sig, siglen, fd); 184 } 185 186 int 187 pkgsign_verify_cert(const struct pkgsign_ctx *ctx, unsigned char *key, size_t keylen, 188 unsigned char *sig, size_t siglen, int fd) 189 { 190 191 return (*ctx->impl->pi_ops->pkgsign_verify_cert)(ctx, key, keylen, sig, 192 siglen, fd); 193 } 194 195 const char * 196 pkgsign_impl_name(const struct pkgsign_ctx *ctx) 197 { 198 199 return (ctx->impl->pi_name); 200 } 201 202 int 203 pkgsign_generate(struct pkgsign_ctx *ctx, const struct iovec *iov, int niov) 204 { 205 206 if (ctx->impl->pi_ops->pkgsign_generate == NULL) 207 return (EPKG_OPNOTSUPP); 208 return (*ctx->impl->pi_ops->pkgsign_generate)(ctx, iov, niov); 209 } 210 211 int 212 pkgsign_sign_data(struct pkgsign_ctx *ctx, const unsigned char *msg, size_t msgsz, 213 unsigned char **sig, size_t *siglen) 214 { 215 216 if (ctx->impl->pi_ops->pkgsign_sign_data == NULL) 217 return (EPKG_OPNOTSUPP); 218 return (*ctx->impl->pi_ops->pkgsign_sign_data)(ctx, msg, msgsz, sig, siglen); 219 } 220 221 int 222 pkgsign_keyinfo(struct pkgsign_ctx *ctx, struct iovec **iov, int *niov) 223 { 224 225 if (ctx->impl->pi_ops->pkgsign_keyinfo == NULL) 226 return (EPKG_OPNOTSUPP); 227 return (*ctx->impl->pi_ops->pkgsign_keyinfo)(ctx, iov, niov); 228 } 229 230 int 231 pkgsign_pubkey(struct pkgsign_ctx *ctx, char **pubkey, size_t *pubkeylen) 232 { 233 234 if (ctx->impl->pi_ops->pkgsign_pubkey == NULL) 235 return (EPKG_OPNOTSUPP); 236 return (*ctx->impl->pi_ops->pkgsign_pubkey)(ctx, pubkey, pubkeylen); 237 }