Branch data Line data Source code
1 : : /* certauth.c - Certification authority functions
2 : : *
3 : : * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
4 : : * License: This software may be distributed under the same license
5 : : * terms as openssl (i.e. free, but mandatory attribution).
6 : : *
7 : : * This borrows quite heavily ideas and control flow from openssl/apps/ca.c
8 : : * by Eric A. Young. You could say this file is destillation of Eric's
9 : : * work with many of the parameters hard wired:
10 : : *
11 : : * - MD5 hash
12 : : *
13 : : * 25.10.1999, Created. --Sampo
14 : : */
15 : :
16 : : /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
17 : : * All rights reserved.
18 : : *
19 : : * This package is an SSL implementation written
20 : : * by Eric Young (eay@cryptsoft.com).
21 : : * The implementation was written so as to conform with Netscapes SSL.
22 : : *
23 : : * This library is free for commercial and non-commercial use as long as
24 : : * the following conditions are aheared to. The following conditions
25 : : * apply to all code found in this distribution, be it the RC4, RSA,
26 : : * lhash, DES, etc., code; not just the SSL code. The SSL documentation
27 : : * included with this distribution is covered by the same copyright terms
28 : : * except that the holder is Tim Hudson (tjh@cryptsoft.com).
29 : : *
30 : : * Copyright remains Eric Young's, and as such any Copyright notices in
31 : : * the code are not to be removed.
32 : : * If this package is used in a product, Eric Young should be given attribution
33 : : * as the author of the parts of the library used.
34 : : * This can be in the form of a textual message at program startup or
35 : : * in documentation (online or textual) provided with the package.
36 : : *
37 : : * Redistribution and use in source and binary forms, with or without
38 : : * modification, are permitted provided that the following conditions
39 : : * are met:
40 : : * 1. Redistributions of source code must retain the copyright
41 : : * notice, this list of conditions and the following disclaimer.
42 : : * 2. Redistributions in binary form must reproduce the above copyright
43 : : * notice, this list of conditions and the following disclaimer in the
44 : : * documentation and/or other materials provided with the distribution.
45 : : * 3. All advertising materials mentioning features or use of this software
46 : : * must display the following acknowledgement:
47 : : * "This product includes cryptographic software written by
48 : : * Eric Young (eay@cryptsoft.com)"
49 : : * The word 'cryptographic' can be left out if the rouines from the library
50 : : * being used are not cryptographic related :-).
51 : : * 4. If you include any Windows specific code (or a derivative thereof) from
52 : : * the apps directory (application code) you must include an acknowledgement:
53 : : * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
54 : : *
55 : : * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
56 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
59 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 : : * SUCH DAMAGE.
66 : : *
67 : : * The licence and distribution terms for any publically available version or
68 : : * derivative of this code cannot be changed. i.e. this code cannot simply be
69 : : * copied and put under another distribution licence
70 : : * [including the GNU Public Licence.]
71 : : */
72 : :
73 : : #include "platform.h"
74 : : #include <stdio.h>
75 : : #include <string.h>
76 : : #include <time.h>
77 : :
78 : : #ifdef __MWERKS__
79 : : # include "macglue.h"
80 : : #endif
81 : :
82 : : #include "logprint.h"
83 : :
84 : : #include <openssl/crypto.h>
85 : : #include <openssl/buffer.h>
86 : : #include <openssl/err.h>
87 : : #include <openssl/rand.h>
88 : : #include <openssl/conf.h>
89 : : #include <openssl/bio.h>
90 : : #include <openssl/objects.h>
91 : : #include <openssl/asn1.h>
92 : : #include <openssl/pem.h>
93 : : #include <openssl/evp.h>
94 : : #include <openssl/x509.h>
95 : : #include <openssl/x509v3.h>
96 : : #include <openssl/pkcs12.h>
97 : :
98 : : #define SMIME_INTERNALS /* we want also our internal helper functions */
99 : : #include "smimeutil.h"
100 : :
101 : : /* Adds some of the most commonly wanted extensions
102 : : *
103 : : * Examples:
104 : : * basic_constraints: CA:TRUE,pathlen:3
105 : : * cert_type: client,server,email,objsign,sslCA,emailCA,objCA
106 : : * key_usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
107 : : * comment: dont trust me ;-)
108 : : */
109 : :
110 : : /* Called by: certification_authority, keygen */
111 : : int
112 : : add_some_X509v3_extensions(X509* cert,
113 : : const char* basic_constraints,
114 : : const char* cert_type,
115 : : const char* key_usage,
116 : : const char* comment)
117 : 2 : {
118 : : X509_EXTENSION* ext;
119 : :
120 [ - + ]: 2 : if (!cert) GOTO_ERR("NULL arg");
121 : :
122 [ + - ]: 2 : if (basic_constraints) {
123 [ - + ]: 2 : if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
124 : : (char*)basic_constraints)))
125 : 0 : GOTO_ERR("X509V3_EXT_conf_nid");
126 : 2 : X509_add_ext(cert, ext, -1);
127 : : }
128 : :
129 [ + - ]: 2 : if (cert_type) {
130 [ - + ]: 2 : if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_cert_type,
131 : : (char*)cert_type)))
132 : 0 : GOTO_ERR("X509V3_EXT_conf_nid");
133 : 2 : X509_add_ext(cert, ext, -1);
134 : : }
135 : :
136 [ + - ]: 2 : if (key_usage) {
137 [ - + ]: 2 : if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
138 : : (char*)key_usage)))
139 : 0 : GOTO_ERR("X509V3_EXT_conf_nid");
140 : 2 : X509_add_ext(cert, ext, -1);
141 : : }
142 : :
143 [ + - ]: 2 : if (comment) {
144 [ - + ]: 2 : if (!(ext = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_comment,
145 : : (char*)comment)))
146 : 0 : GOTO_ERR("X509V3_EXT_conf_nid");
147 : 2 : X509_add_ext(cert, ext, -1);
148 : : }
149 : 2 : return 0;
150 : 0 : err:
151 : 0 : return -1;
152 : : }
153 : :
154 : : /* Perform certificate construction and signing functionality of
155 : : * a CA. Note that there is much more to it than that: you need
156 : : * to ensure uniqueness of serial numbers, you need to keep database
157 : : * of issued certificates, you need to enforce your policy wrt DNs, etc.
158 : : * Last four args correspond to x509v3 extensions. If you pass NULL
159 : : * the extension will not be included. Examples:
160 : : *
161 : : * basic_constraints: CA:TRUE,pathlen:3
162 : : * cert_type: client,server,email,objsign,sslCA,emailCA,objCA
163 : : * key_usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
164 : : * comment: dont trust me ;-)
165 : : *
166 : : * Start date is either "today" or xxx
167 : : * End date is either "days:123" or xxx
168 : : */
169 : :
170 : : /* Called by: smime_ca */
171 : : X509* /* returns signed certificate, or NULL if error */
172 : : certification_authority(X509* ca_cert,
173 : : EVP_PKEY* ca_pkey,
174 : : X509_REQ* req,
175 : : const char* start_date, /* today or yymmddhhmmss */
176 : : const char* end_date, /* days:123 or yymmddhhmmss */
177 : : long serial,
178 : : const char* basic_constraints,
179 : : const char* cert_type,
180 : : const char* key_usage,
181 : : const char* comment)
182 : 0 : {
183 : 0 : X509* cert = NULL; /* This will be the new born certificate! */
184 : 0 : X509_NAME* name = NULL;
185 : 0 : EVP_PKEY* req_pkey = NULL;
186 : : int days;
187 : :
188 [ # # # # : 0 : if (!ca_cert || !ca_pkey || !req || !start_date || !end_date)
# # # # #
# ]
189 : 0 : GOTO_ERR("NULL arg(s)");
190 : 0 : X509V3_add_standard_extensions();
191 : :
192 : : /* alloc */
193 : :
194 [ # # ]: 0 : if (!(cert = X509_new())) GOTO_ERR("no memory?");
195 : :
196 [ # # # # : 0 : if (basic_constraints || cert_type || key_usage || comment) {
# # # # ]
197 [ # # ]: 0 : if (!X509_set_version(cert,2)) GOTO_ERR("cant set cert version 3");
198 : : }
199 : :
200 : : /* set names */
201 : :
202 [ # # ]: 0 : if (!ASN1_INTEGER_set(cert->cert_info->serialNumber, serial))
203 : 0 : GOTO_ERR("cant set serial number");
204 [ # # ]: 0 : if (!(name = X509_get_subject_name(ca_cert)))
205 : 0 : GOTO_ERR("cant get issuer name");
206 [ # # ]: 0 : if (!X509_set_issuer_name(cert,name)) GOTO_ERR("cant set issuer name");
207 : :
208 [ # # ]: 0 : if (!(name = X509_REQ_get_subject_name(req)))
209 : 0 : GOTO_ERR("cant get request subject name");
210 [ # # ]: 0 : if (!X509_set_subject_name(cert,name)) GOTO_ERR("cant set subject name");
211 : :
212 : : /* set dates */
213 : :
214 [ # # ]: 0 : if (strcmp(start_date,"today") == 0)
215 : 0 : X509_gmtime_adj(X509_get_notBefore(cert),0);
216 : : else
217 : 0 : ASN1_UTCTIME_set_string(X509_get_notBefore(cert),(char*)start_date);
218 : :
219 [ # # ]: 0 : if (!memcmp(end_date, "days:", 5)) {
220 : 0 : days = atoi(end_date + 5);
221 : 0 : X509_gmtime_adj(X509_get_notAfter(cert),(long)60*60*24*days);
222 : : } else
223 : 0 : ASN1_UTCTIME_set_string(X509_get_notAfter(cert),(char*)end_date);
224 : :
225 : : /* Copy the public key from the request */
226 : :
227 [ # # ]: 0 : if (!(req_pkey=X509_REQ_get_pubkey(req)))
228 : 0 : GOTO_ERR("cant get public key from request");
229 [ # # ]: 0 : if (!X509_set_pubkey(cert, req_pkey)) GOTO_ERR("cant set public key");
230 : 0 : EVP_PKEY_free(req_pkey);
231 : 0 : req_pkey = NULL;
232 : :
233 : : /* Set extensions */
234 : :
235 [ # # ]: 0 : if (add_some_X509v3_extensions(cert,basic_constraints, cert_type,
236 : 0 : key_usage, comment)==-1) goto err;
237 : :
238 : : /* Sign it into a certificate */
239 : :
240 : : LOG_PRINT("ca signing x509");
241 [ # # ]: 0 : if (!(X509_sign(cert, ca_pkey, EVP_md5()))) GOTO_ERR("X509_sign");
242 : :
243 : 0 : X509V3_EXT_cleanup();
244 : 0 : OBJ_cleanup();
245 : 0 : return cert;
246 : :
247 : 0 : err:
248 : 0 : X509V3_EXT_cleanup();
249 : 0 : OBJ_cleanup();
250 [ # # ]: 0 : if (req_pkey) EVP_PKEY_free(req_pkey);
251 [ # # ]: 0 : if (cert) X509_free(cert);
252 : 0 : return NULL;
253 : : }
254 : :
255 : : /* Called by: main */
256 : : char* /* returns pem encoded certificate, or NULL if error */
257 : : smime_ca(const char* ca_id_pem,
258 : : const char* passwd,
259 : : const char* req_pem,
260 : : const char* start_date,
261 : : const char* end_date,
262 : : long serial,
263 : : const char* basic_constraints,
264 : : const char* cert_type,
265 : : const char* key_usage,
266 : : const char* comment)
267 : 1 : {
268 : 1 : X509* ca_cert = NULL;
269 : 1 : X509* new_cert = NULL;
270 : 1 : X509_REQ* req = NULL;
271 : 1 : EVP_PKEY* ca_pkey = NULL;
272 : 1 : char* ret = NULL;
273 : :
274 [ + - + - : 1 : if (!ca_id_pem || !passwd || !req_pem) GOTO_ERR("NULL arg(s)");
- + ]
275 : :
276 [ - + ]: 1 : if (!(ca_pkey = open_private_key(ca_id_pem, passwd))) goto err;
277 [ # # ]: 0 : if (!(ca_cert = extract_certificate(ca_id_pem))) goto err;
278 [ # # ]: 0 : if (!(req = extract_request(req_pem))) goto err;
279 : :
280 [ # # ]: 0 : if (!(new_cert = certification_authority(ca_cert, ca_pkey, req,
281 : : start_date, end_date, serial,
282 : : basic_constraints, cert_type,
283 : 0 : key_usage, comment))) goto err;
284 : 0 : write_certificate(new_cert, &ret);
285 : :
286 : 1 : err:
287 [ - + ]: 1 : if (ca_cert) X509_free(ca_cert);
288 [ - + ]: 1 : if (req) X509_REQ_free(req);
289 [ - + ]: 1 : if (ca_pkey) EVP_PKEY_free(ca_pkey);
290 [ - + ]: 1 : if (new_cert) X509_free(new_cert);
291 : 1 : return ret;
292 : : }
293 : :
294 : : /* EOF - certauth.c */
|