/ libpkg / pkgsign.c
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  }