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