1 /* $NetBSD: pkcs7.c,v 1.3 2009/02/16 20:59:11 joerg Exp $ */
10 __RCSID("$NetBSD: pkcs7.c,v 1.3 2009/02/16 20:59:11 joerg Exp $");
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
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.
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>
55 #define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
59 #define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
62 static const int pkg_key_usage
= XKU_CODE_SIGN
| XKU_SMIME
;
67 if ((cert
->ex_flags
& EXFLAG_KUSAGE
) != 0 &&
68 (cert
->ex_kusage
& KU_KEY_CERT_SIGN
) != KU_KEY_CERT_SIGN
)
70 if ((cert
->ex_flags
& EXFLAG_BCONS
) != 0)
71 return (cert
->ex_flags
& EXFLAG_CA
) == EXFLAG_CA
;
72 if ((cert
->ex_flags
& (EXFLAG_V1
|EXFLAG_SS
)) == (EXFLAG_V1
|EXFLAG_SS
))
74 if ((cert
->ex_flags
& EXFLAG_KUSAGE
) != 0)
76 if ((cert
->ex_flags
& EXFLAG_NSCERT
) != 0 &&
77 (cert
->ex_nscert
& NS_ANY_CA
) != 0)
82 static STACK_OF(X509
) *
83 file_to_certs(const char *file
)
86 STACK_OF(X509
) *certs
;
89 if ((f
= fopen(file
, "r")) == NULL
) {
90 warn("open failed %s", file
);
94 certs
= sk_X509_new_null();
98 cert
= PEM_read_X509(f
, NULL
, NULL
, NULL
);
100 ret
= ERR_GET_REASON(ERR_peek_error());
101 if (ret
== PEM_R_NO_START_LINE
) {
102 /* End of file reached. no error */
107 warnx("Can't read certificate in file: %s", file
);
110 sk_X509_insert(certs
, cert
, sk_X509_num(certs
));
115 if (sk_X509_num(certs
) == 0) {
118 warnx("No certificate found in file %s", file
);
125 easy_pkcs7_verify(const char *content
, size_t len
,
126 const char *signature
, size_t signature_len
,
127 const char *anchor
, int is_pkg
)
129 STACK_OF(X509
) *cert_chain
, *signers
;
137 OpenSSL_add_all_algorithms();
138 ERR_load_crypto_strings();
143 cert_chain
= file_to_certs(cert_chain_file
);
147 store
= X509_STORE_new();
149 sk_X509_free(cert_chain
);
150 warnx("Failed to create certificate store");
154 X509_STORE_load_locations(store
, anchor
, NULL
);
156 in
= BIO_new_mem_buf(__UNCONST(content
), len
);
157 sig
= BIO_new_mem_buf(__UNCONST(signature
), signature_len
);
160 p7
= PEM_read_bio_PKCS7(sig
, NULL
, NULL
, NULL
);
162 warnx("Failed to parse the signature");
166 if (PKCS7_verify(p7
, cert_chain
, store
, in
, NULL
, 0) != 1) {
167 warnx("Failed to verify signature");
171 signers
= PKCS7_get0_signers(p7
, NULL
, 0);
172 if (signers
== NULL
) {
173 warnx("Failed to get signers");
177 if (sk_X509_num(signers
) == 0) {
178 warnx("No signers found");
182 for (i
= 0; i
< sk_X509_num(signers
); i
++) {
183 /* Compute ex_xkusage */
184 X509_check_purpose(sk_X509_value(signers
, i
), -1, -1);
186 if (check_ca(sk_X509_value(signers
, i
))) {
187 warnx("CA keys are not valid for signatures");
191 if (sk_X509_value(signers
, i
)->ex_xkusage
!= pkg_key_usage
) {
192 warnx("Certificate must have CODE SIGNING "
193 "and EMAIL PROTECTION property");
197 if (sk_X509_value(signers
, i
)->ex_xkusage
!= 0) {
198 warnx("Certificate must not have any property");
204 printf("Sigature ok, signed by:\n");
206 for (i
= 0; i
< sk_X509_num(signers
); i
++) {
207 name
= X509_get_subject_name(sk_X509_value(signers
, i
));
208 subject
= X509_NAME_oneline(name
, NULL
, 0);
210 printf("\t%s\n", subject
);
212 OPENSSL_free(subject
);
218 sk_X509_free(cert_chain
);
219 sk_X509_free(signers
);
220 X509_STORE_free(store
);
230 ssl_pass_cb(char *buf
, int size
, int rwflag
, void *u
)
233 if (EVP_read_pw_string(buf
, size
, "Passphrase :", 0)) {
234 #if OPENSSL_VERSION >= 0x0090608fL
235 OPENSSL_cleanse(buf
, size
);
237 memset(buf
, 0, size
);
245 easy_pkcs7_sign(const char *content
, size_t len
,
246 char **signature
, size_t *signature_len
,
247 const char *key_file
, const char *cert_file
)
251 STACK_OF(X509
) *c
, *cert_chain
;
252 EVP_PKEY
*private_key
;
258 OpenSSL_add_all_algorithms();
259 ERR_load_crypto_strings();
266 c
= file_to_certs(cert_file
);
268 if (sk_X509_num(c
) != 1) {
269 warnx("More then one certificate in the certificate file");
272 certificate
= sk_X509_value(c
, 0);
274 /* Compute ex_kusage */
275 X509_check_purpose(certificate
, -1, 0);
277 if (check_ca(certificate
)) {
278 warnx("CA keys are not valid for signatures");
282 if (certificate
->ex_xkusage
!= pkg_key_usage
) {
283 warnx("Certificate must have CODE SIGNING "
284 "and EMAIL PROTECTION property");
289 cert_chain
= file_to_certs(cert_chain_file
);
291 if ((f
= fopen(key_file
, "r")) == NULL
) {
292 warn("Failed to open private key file %s", key_file
);
295 private_key
= PEM_read_PrivateKey(f
, NULL
, ssl_pass_cb
, NULL
);
297 if (private_key
== NULL
) {
298 warnx("Can't read private key: %s", key_file
);
302 if (X509_check_private_key(certificate
, private_key
) != 1) {
303 warnx("The private key %s doesn't match the certificate %s",
304 key_file
, cert_file
);
308 in
= BIO_new_mem_buf(__UNCONST(content
), len
);
310 p7
= PKCS7_sign(certificate
, private_key
, cert_chain
, in
,
311 PKCS7_DETACHED
|PKCS7_NOATTR
|PKCS7_BINARY
);
313 warnx("Failed to create signature structure");
317 out
= BIO_new(BIO_s_mem());
318 PEM_write_bio_PKCS7(out
, p7
);
319 *signature_len
= BIO_get_mem_data(out
, &tmp_sig
);
320 *signature
= xmalloc(*signature_len
);
321 memcpy(*signature
, tmp_sig
, *signature_len
);
330 sk_X509_free(cert_chain
);
331 EVP_PKEY_free(private_key
);