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