Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / pkg_install / dist / lib / pkcs7.c
blob0fd4f245c1eed42994d368b77e5d4eb916511ecc
1 /* $NetBSD: pkcs7.c,v 1.5 2009/08/02 17:56:45 joerg Exp $ */
2 #if HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include <nbcompat.h>
6 #if HAVE_SYS_CDEFS_H
7 #include <sys/cdefs.h>
8 #endif
10 __RCSID("$NetBSD: pkcs7.c,v 1.5 2009/08/02 17:56:45 joerg Exp $");
12 /*-
13 * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc.
14 * All rights reserved.
16 * This code is derived from software contributed to The NetBSD Foundation
17 * by Love Hörnquist Åstrand <lha@it.su.se>
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
41 #if HAVE_ERR_H
42 #include <err.h>
43 #endif
45 #include <openssl/pkcs7.h>
46 #include <openssl/evp.h>
47 #include <openssl/x509.h>
48 #include <openssl/x509v3.h>
49 #include <openssl/pem.h>
50 #include <openssl/err.h>
52 #include "lib.h"
54 #ifndef NS_ANY_CA
55 #define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
56 #endif
58 static const unsigned int pkg_key_usage = XKU_CODE_SIGN | XKU_SMIME;
60 static int
61 check_ca(X509 *cert)
63 if ((cert->ex_flags & EXFLAG_KUSAGE) != 0 &&
64 (cert->ex_kusage & KU_KEY_CERT_SIGN) != KU_KEY_CERT_SIGN)
65 return 0;
66 if ((cert->ex_flags & EXFLAG_BCONS) != 0)
67 return (cert->ex_flags & EXFLAG_CA) == EXFLAG_CA;
68 if ((cert->ex_flags & (EXFLAG_V1|EXFLAG_SS)) == (EXFLAG_V1|EXFLAG_SS))
69 return 1;
70 if ((cert->ex_flags & EXFLAG_KUSAGE) != 0)
71 return 1;
72 if ((cert->ex_flags & EXFLAG_NSCERT) != 0 &&
73 (cert->ex_nscert & NS_ANY_CA) != 0)
74 return 1;
75 return 0;
78 static STACK_OF(X509) *
79 file_to_certs(const char *file)
81 unsigned long ret;
82 STACK_OF(X509) *certs;
83 FILE *f;
85 if ((f = fopen(file, "r")) == NULL) {
86 warn("open failed %s", file);
87 return NULL;
90 certs = sk_X509_new_null();
91 for (;;) {
92 X509 *cert;
94 cert = PEM_read_X509(f, NULL, NULL, NULL);
95 if (cert == NULL) {
96 ret = ERR_GET_REASON(ERR_peek_error());
97 if (ret == PEM_R_NO_START_LINE) {
98 /* End of file reached. no error */
99 ERR_clear_error();
100 break;
102 sk_X509_free(certs);
103 warnx("Can't read certificate in file: %s", file);
104 fclose(f);
105 return NULL;
107 sk_X509_insert(certs, cert, sk_X509_num(certs));
110 fclose(f);
112 if (sk_X509_num(certs) == 0) {
113 sk_X509_free(certs);
114 certs = NULL;
115 warnx("No certificate found in file %s", file);
118 return certs;
122 easy_pkcs7_verify(const char *content, size_t len,
123 const char *signature, size_t signature_len,
124 const char *anchor, int is_pkg)
126 STACK_OF(X509) *cert_chain, *signers;
127 X509_STORE *store;
128 BIO *sig, *in;
129 PKCS7 *p7;
130 int i, status;
131 X509_NAME *name;
132 char *subject;
134 OpenSSL_add_all_algorithms();
135 ERR_load_crypto_strings();
137 status = -1;
139 if (cert_chain_file)
140 cert_chain = file_to_certs(cert_chain_file);
141 else
142 cert_chain = NULL;
144 store = X509_STORE_new();
145 if (store == NULL) {
146 sk_X509_free(cert_chain);
147 warnx("Failed to create certificate store");
148 return -1;
151 X509_STORE_load_locations(store, anchor, NULL);
153 in = BIO_new_mem_buf(__UNCONST(content), len);
154 sig = BIO_new_mem_buf(__UNCONST(signature), signature_len);
155 signers = NULL;
157 p7 = PEM_read_bio_PKCS7(sig, NULL, NULL, NULL);
158 if (p7 == NULL) {
159 warnx("Failed to parse the signature");
160 goto cleanup;
163 if (PKCS7_verify(p7, cert_chain, store, in, NULL, 0) != 1) {
164 warnx("Failed to verify signature");
165 goto cleanup;
168 signers = PKCS7_get0_signers(p7, NULL, 0);
169 if (signers == NULL) {
170 warnx("Failed to get signers");
171 goto cleanup;
174 if (sk_X509_num(signers) == 0) {
175 warnx("No signers found");
176 goto cleanup;
179 for (i = 0; i < sk_X509_num(signers); i++) {
180 /* Compute ex_xkusage */
181 X509_check_purpose(sk_X509_value(signers, i), -1, -1);
183 if (check_ca(sk_X509_value(signers, i))) {
184 warnx("CA keys are not valid for signatures");
185 goto cleanup;
187 if (is_pkg) {
188 if (sk_X509_value(signers, i)->ex_xkusage != pkg_key_usage) {
189 warnx("Certificate must have CODE SIGNING "
190 "and EMAIL PROTECTION property");
191 goto cleanup;
193 } else {
194 if (sk_X509_value(signers, i)->ex_xkusage != 0) {
195 warnx("Certificate must not have any property");
196 goto cleanup;
201 printf("Sigature ok, signed by:\n");
203 for (i = 0; i < sk_X509_num(signers); i++) {
204 name = X509_get_subject_name(sk_X509_value(signers, i));
205 subject = X509_NAME_oneline(name, NULL, 0);
207 printf("\t%s\n", subject);
209 OPENSSL_free(subject);
212 status = 0;
214 cleanup:
215 sk_X509_free(cert_chain);
216 sk_X509_free(signers);
217 X509_STORE_free(store);
219 PKCS7_free(p7);
220 BIO_free(in);
221 BIO_free(sig);
223 return status;
226 static int
227 ssl_pass_cb(char *buf, int size, int rwflag, void *u)
230 if (EVP_read_pw_string(buf, size, "Passphrase :", 0)) {
231 #if OPENSSL_VERSION >= 0x0090608fL
232 OPENSSL_cleanse(buf, size);
233 #else
234 memset(buf, 0, size);
235 #endif
236 return 0;
238 return strlen(buf);
242 easy_pkcs7_sign(const char *content, size_t len,
243 char **signature, size_t *signature_len,
244 const char *key_file, const char *cert_file)
246 FILE *f;
247 X509 *certificate;
248 STACK_OF(X509) *c, *cert_chain;
249 EVP_PKEY *private_key;
250 char *tmp_sig;
251 BIO *out, *in;
252 PKCS7 *p7;
253 int status;
255 OpenSSL_add_all_algorithms();
256 ERR_load_crypto_strings();
258 status = -1;
259 private_key = NULL;
260 cert_chain = NULL;
261 in = NULL;
263 c = file_to_certs(cert_file);
265 if (sk_X509_num(c) != 1) {
266 warnx("More then one certificate in the certificate file");
267 goto cleanup;
269 certificate = sk_X509_value(c, 0);
271 /* Compute ex_kusage */
272 X509_check_purpose(certificate, -1, 0);
274 if (check_ca(certificate)) {
275 warnx("CA keys are not valid for signatures");
276 goto cleanup;
279 if (certificate->ex_xkusage != pkg_key_usage) {
280 warnx("Certificate must have CODE SIGNING "
281 "and EMAIL PROTECTION property");
282 goto cleanup;
285 if (cert_chain_file)
286 cert_chain = file_to_certs(cert_chain_file);
288 if ((f = fopen(key_file, "r")) == NULL) {
289 warn("Failed to open private key file %s", key_file);
290 goto cleanup;
292 private_key = PEM_read_PrivateKey(f, NULL, ssl_pass_cb, NULL);
293 fclose(f);
294 if (private_key == NULL) {
295 warnx("Can't read private key: %s", key_file);
296 goto cleanup;
299 if (X509_check_private_key(certificate, private_key) != 1) {
300 warnx("The private key %s doesn't match the certificate %s",
301 key_file, cert_file);
302 goto cleanup;
305 in = BIO_new_mem_buf(__UNCONST(content), len);
307 p7 = PKCS7_sign(certificate, private_key, cert_chain, in,
308 PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
309 if (p7 == NULL) {
310 warnx("Failed to create signature structure");
311 goto cleanup;
314 out = BIO_new(BIO_s_mem());
315 PEM_write_bio_PKCS7(out, p7);
316 *signature_len = BIO_get_mem_data(out, &tmp_sig);
317 *signature = xmalloc(*signature_len);
318 memcpy(*signature, tmp_sig, *signature_len);
319 BIO_free_all(out);
321 PKCS7_free(p7);
323 status = 0;
325 cleanup:
326 sk_X509_free(c);
327 sk_X509_free(cert_chain);
328 EVP_PKEY_free(private_key);
329 BIO_free(in);
331 return status;