1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2012-2014 Baptiste Daroussin <bapt@FreeBSD.org>
5 * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/types.h>
32
33 #include <err.h>
34 #include <stdbool.h>
35 #include <string.h>
36
37 #include <openssl/err.h>
38 #include <openssl/ssl.h>
39
40 #include "pkg.h"
41
42 #include "config.h"
43 #include "hash.h"
44
45 static EVP_PKEY *
load_public_key_file(const char * file)46 load_public_key_file(const char *file)
47 {
48 EVP_PKEY *pkey;
49 BIO *bp;
50 char errbuf[1024];
51
52 bp = BIO_new_file(file, "r");
53 if (!bp)
54 errx(EXIT_FAILURE, "Unable to read %s", file);
55
56 if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL)
57 warnx("ici: %s", ERR_error_string(ERR_get_error(), errbuf));
58
59 BIO_free(bp);
60
61 return (pkey);
62 }
63
64 static EVP_PKEY *
load_public_key_buf(const unsigned char * cert,int certlen)65 load_public_key_buf(const unsigned char *cert, int certlen)
66 {
67 EVP_PKEY *pkey;
68 BIO *bp;
69 char errbuf[1024];
70
71 bp = BIO_new_mem_buf(__DECONST(void *, cert), certlen);
72
73 if ((pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL)) == NULL)
74 warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
75
76 BIO_free(bp);
77
78 return (pkey);
79 }
80
81 static bool
rsa_verify_data(const struct pkgsign_ctx * ctx __unused,const char * data,size_t datasz,const char * sigfile,const unsigned char * key,int keylen,unsigned char * sig,int siglen)82 rsa_verify_data(const struct pkgsign_ctx *ctx __unused,
83 const char *data, size_t datasz, const char *sigfile,
84 const unsigned char *key, int keylen, unsigned char *sig, int siglen)
85 {
86 EVP_MD_CTX *mdctx;
87 EVP_PKEY *pkey;
88 char errbuf[1024];
89 bool ret;
90
91 pkey = NULL;
92 mdctx = NULL;
93 ret = false;
94 SSL_load_error_strings();
95
96 if (sigfile != NULL) {
97 if ((pkey = load_public_key_file(sigfile)) == NULL) {
98 warnx("Error reading public key");
99 goto cleanup;
100 }
101 } else {
102 if ((pkey = load_public_key_buf(key, keylen)) == NULL) {
103 warnx("Error reading public key");
104 goto cleanup;
105 }
106 }
107
108 /* Verify signature of the SHA256(pkg) is valid. */
109 if ((mdctx = EVP_MD_CTX_create()) == NULL) {
110 warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
111 goto error;
112 }
113
114 if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
115 warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
116 goto error;
117 }
118 if (EVP_DigestVerifyUpdate(mdctx, data, datasz) != 1) {
119 warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
120 goto error;
121 }
122
123 if (EVP_DigestVerifyFinal(mdctx, sig, siglen) != 1) {
124 warnx("%s", ERR_error_string(ERR_get_error(), errbuf));
125 goto error;
126 }
127
128 ret = true;
129 printf("done\n");
130 goto cleanup;
131
132 error:
133 printf("failed\n");
134
135 cleanup:
136 if (pkey)
137 EVP_PKEY_free(pkey);
138 if (mdctx)
139 EVP_MD_CTX_destroy(mdctx);
140 ERR_free_strings();
141
142 return (ret);
143 }
144
145 static bool
rsa_verify_cert(const struct pkgsign_ctx * ctx __unused,int fd,const char * sigfile,const unsigned char * key,int keylen,unsigned char * sig,int siglen)146 rsa_verify_cert(const struct pkgsign_ctx *ctx __unused, int fd,
147 const char *sigfile, const unsigned char *key, int keylen,
148 unsigned char *sig, int siglen)
149 {
150 char *sha256;
151 bool ret;
152
153 sha256 = NULL;
154
155 /* Compute SHA256 of the package. */
156 if (lseek(fd, 0, 0) == -1) {
157 warn("lseek");
158 return (false);
159 }
160 if ((sha256 = sha256_fd(fd)) == NULL) {
161 warnx("Error creating SHA256 hash for package");
162 return (false);
163 }
164
165 ret = rsa_verify_data(ctx, sha256, strlen(sha256), sigfile, key, keylen,
166 sig, siglen);
167 free(sha256);
168
169 return (ret);
170 }
171
172 const struct pkgsign_ops pkgsign_rsa = {
173 .pkgsign_verify_cert = rsa_verify_cert,
174 .pkgsign_verify_data = rsa_verify_data,
175 };
176