1 /* $NetBSD: pkcs7.c,v 1.5 2009/08/02 17:56:45 joerg Exp $ */
10 __RCSID("$NetBSD: pkcs7.c,v 1.5 2009/08/02 17:56:45 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 NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
58 static const unsigned int pkg_key_usage
= XKU_CODE_SIGN
| XKU_SMIME
;
63 if ((cert
->ex_flags
& EXFLAG_KUSAGE
) != 0 &&
64 (cert
->ex_kusage
& KU_KEY_CERT_SIGN
) != KU_KEY_CERT_SIGN
)
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
))
70 if ((cert
->ex_flags
& EXFLAG_KUSAGE
) != 0)
72 if ((cert
->ex_flags
& EXFLAG_NSCERT
) != 0 &&
73 (cert
->ex_nscert
& NS_ANY_CA
) != 0)
78 static STACK_OF(X509
) *
79 file_to_certs(const char *file
)
82 STACK_OF(X509
) *certs
;
85 if ((f
= fopen(file
, "r")) == NULL
) {
86 warn("open failed %s", file
);
90 certs
= sk_X509_new_null();
94 cert
= PEM_read_X509(f
, NULL
, NULL
, NULL
);
96 ret
= ERR_GET_REASON(ERR_peek_error());
97 if (ret
== PEM_R_NO_START_LINE
) {
98 /* End of file reached. no error */
103 warnx("Can't read certificate in file: %s", file
);
107 sk_X509_insert(certs
, cert
, sk_X509_num(certs
));
112 if (sk_X509_num(certs
) == 0) {
115 warnx("No certificate found in file %s", file
);
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
;
134 OpenSSL_add_all_algorithms();
135 ERR_load_crypto_strings();
140 cert_chain
= file_to_certs(cert_chain_file
);
144 store
= X509_STORE_new();
146 sk_X509_free(cert_chain
);
147 warnx("Failed to create certificate store");
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
);
157 p7
= PEM_read_bio_PKCS7(sig
, NULL
, NULL
, NULL
);
159 warnx("Failed to parse the signature");
163 if (PKCS7_verify(p7
, cert_chain
, store
, in
, NULL
, 0) != 1) {
164 warnx("Failed to verify signature");
168 signers
= PKCS7_get0_signers(p7
, NULL
, 0);
169 if (signers
== NULL
) {
170 warnx("Failed to get signers");
174 if (sk_X509_num(signers
) == 0) {
175 warnx("No signers found");
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");
188 if (sk_X509_value(signers
, i
)->ex_xkusage
!= pkg_key_usage
) {
189 warnx("Certificate must have CODE SIGNING "
190 "and EMAIL PROTECTION property");
194 if (sk_X509_value(signers
, i
)->ex_xkusage
!= 0) {
195 warnx("Certificate must not have any property");
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
);
215 sk_X509_free(cert_chain
);
216 sk_X509_free(signers
);
217 X509_STORE_free(store
);
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
);
234 memset(buf
, 0, size
);
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
)
248 STACK_OF(X509
) *c
, *cert_chain
;
249 EVP_PKEY
*private_key
;
255 OpenSSL_add_all_algorithms();
256 ERR_load_crypto_strings();
263 c
= file_to_certs(cert_file
);
265 if (sk_X509_num(c
) != 1) {
266 warnx("More then one certificate in the certificate file");
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");
279 if (certificate
->ex_xkusage
!= pkg_key_usage
) {
280 warnx("Certificate must have CODE SIGNING "
281 "and EMAIL PROTECTION property");
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
);
292 private_key
= PEM_read_PrivateKey(f
, NULL
, ssl_pass_cb
, NULL
);
294 if (private_key
== NULL
) {
295 warnx("Can't read private key: %s", key_file
);
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
);
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
);
310 warnx("Failed to create signature structure");
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
);
327 sk_X509_free(cert_chain
);
328 EVP_PKEY_free(private_key
);