1 /* -*- mode: c; c-file-style:"stroustrup"; -*- */
2 
3 /*
4  * Copyright (c) 2018 Mastercard
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <openssl/bio.h>
26 #include <openssl/err.h>
27 #include <openssl/pem.h>
28 #include <openssl/conf.h>
29 #include <openssl/x509.h>
30 #include <openssl/x509v3.h>
31 
32 #include "pkcs11lib.h"
33 
34 
35 static X509_REQ * new_X509_REQ_from_file(char *filename);
36 static void free_X509_REQ_handle(X509_REQ * hndl);
37 
38 
new_X509_REQ_from_file(char * filename)39 static X509_REQ * new_X509_REQ_from_file(char *filename)
40 {
41 
42     X509_REQ * rv = NULL;
43 
44     FILE *fp = NULL;
45 
46     fp = fopen(filename,"rb"); /* open in binary mode */
47 
48     if(fp) {
49 	X509_REQ *csr;
50 
51 	/* try DER first */
52 	csr = d2i_X509_REQ_fp(fp, NULL);
53 	fclose(fp);
54 
55 	if(csr) {
56 	    rv = csr;
57 	} else {
58 	    fp = fopen(filename,"r"); /* reopen in text mode */
59 
60 	    if(fp) {
61 		csr = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
62 		fclose(fp);
63 
64 		if(csr) {
65 		    rv = csr;
66 		}
67 	    } else {
68 		perror("Error opening file");
69 	    }
70 	}
71     } else {
72 	perror("Error opening file");
73     }
74 
75     return rv;
76 }
77 
78 
free_X509_REQ_handle(X509_REQ * hndl)79 inline static void free_X509_REQ_handle(X509_REQ * hndl)
80 {
81     if(hndl) { OPENSSL_free( hndl ); }
82 }
83 
84 
req_add_ext(STACK_OF (X509_EXTENSION)* sk,int nid,char * value)85 static bool req_add_ext(STACK_OF(X509_EXTENSION) *sk, int nid, char *value)
86 {
87     X509_EXTENSION *ex;
88     ex = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
89     if (!ex) {
90 	P_ERR();
91 	return false;
92     }
93 
94     if(!sk_X509_EXTENSION_push(sk, ex)) {
95 	P_ERR();
96 	return false;
97     }
98 
99     return true;
100 }
101 
102 /* public interface */
103 
104 
pkcs11_get_X509_REQ_from_file(char * csrfilename)105 inline x509_req_handle_t *pkcs11_get_X509_REQ_from_file(char *csrfilename) {
106     return (x509_req_handle_t *) new_X509_REQ_from_file(csrfilename);
107 }
108 
x509_req_handle_t_free(x509_req_handle_t * hndl)109 inline void x509_req_handle_t_free(x509_req_handle_t *hndl)
110 {
111     free_X509_REQ_handle((X509_REQ *) hndl);
112 }
113 
pkcs11_masq_X509_REQ(x509_req_handle_t * req,char * dn,bool reverse,char * san[],int sancnt,bool ext_ski)114 bool pkcs11_masq_X509_REQ(x509_req_handle_t *req,
115 			  char *dn,
116 			  bool reverse,
117 			  char *san[],
118 			  int sancnt,
119 			  bool ext_ski)
120 {
121     bool retval = false;
122     EVP_PKEY *pk = NULL;
123     X509_NAME *name=NULL;
124     X509_REQ *xreq = (X509_REQ *)req;
125 
126     STACK_OF(X509_EXTENSION) *exts = NULL;
127 
128     /* step 1: retrieve key type */
129 
130 
131     if(!(pk = X509_REQ_get0_pubkey(xreq))) {
132 	P_ERR();
133 	goto err;
134     }
135 
136     /* step 2: do key-type specific business*/
137     switch(EVP_PKEY_base_id(pk)) {
138 
139     case EVP_PKEY_RSA:
140 	/* hook our crypto to OpenSSL methods */
141 	pkcs11_rsa_method_setup();
142 	pkcs11_rsa_method_pkcs11_context(NULL_PTR, 0, true);
143 	break;
144 
145     case EVP_PKEY_DSA:
146 	/* hook our crypto to OpenSSL methods */
147 	pkcs11_dsa_method_setup();
148 	pkcs11_dsa_method_pkcs11_context(NULL_PTR, 0, true);
149 	break;
150 
151     case EVP_PKEY_EC:
152 	/* hook our crypto to OpenSSL methods */
153 	pkcs11_ecdsa_method_setup();
154 	pkcs11_ecdsa_method_pkcs11_context(NULL_PTR, 0, true);
155 	break;
156 
157     default:
158 	fprintf(stderr, "Error: unsupported signing algorithm\n");
159 	goto err;
160     }
161 
162     /* step 3: parse subject DN (which becomes issuer DN) */
163     if((name = pkcs11_DN_new_from_string(dn, MBSTRING_UTF8, false, reverse))==NULL) {
164 	P_ERR();
165 	goto err;
166     }
167 
168     /* TODO: fix mem leak with previous value? */
169     if (!X509_REQ_set_subject_name(xreq, name)) {
170 	P_ERR();
171 	goto err;
172     }
173 
174     /* next steps are optional, as we do not necessarily have extensions to add */
175     if(ext_ski || sancnt>0) {
176 	/* retrieve extention structure */
177 	if(!(exts = sk_X509_EXTENSION_new_null())) {
178 	    P_ERR();
179 	    goto err;
180 	}
181 
182 	/* step 4: add SAN if specified */
183 	/* TODO extract and error checking */
184 	if(sancnt>0)
185 	{
186 	    int i;
187 	    size_t size=0;
188 	    char *sanfield=NULL;
189 
190 	    for(i=0; i<sancnt; i++) {
191 		size += strlen(san[i]) + 1;	/* we add one for the ',' */
192 	    }
193 	    size++;		/* add a supplementary byte for allowing extra last ',' with strcat() */
194 
195 	    if((sanfield=OPENSSL_malloc(size))!=NULL) {
196 	    sanfield[0]=0;	/* clear first byte */
197 	    for(i=0;i<sancnt;i++) {
198 		strcat(sanfield,san[i]);
199 		strcat(sanfield,",");
200 	    }
201 
202 	    sanfield[strlen(sanfield)-1] = '\0'; /* erase last comma */
203 	    req_add_ext(exts, NID_subject_alt_name, sanfield);
204 	    OPENSSL_free(sanfield);
205 	    }
206 	}
207 
208 	/* step 5: add SKI if specified */
209 	if(ext_ski) {
210 	    char *value=NULL;
211 	    uint8_t *ski=NULL;
212 	    size_t ski_len=0;
213 
214 	    if((ski_len=pkcs11_new_SKI_value_from_pubk(pk, &ski)) ==0 ) {
215 		fprintf(stderr, "Error: could not determine SKI from public key\n");
216 		goto err;
217 	    }
218 	    /* retrieve the value */
219 
220 	    value=(char *) OPENSSL_zalloc( ski_len * 2  + 1);
221 
222 	    if(value) {
223 		int i;
224 
225 		for(i=0; i<ski_len; i++) {
226 		    sprintf(&value[i*2], "%2.2x", ski[i]);
227 		}
228 
229 		req_add_ext(exts, NID_subject_key_identifier, &value[0]);
230 		OPENSSL_free(value);
231 	    }
232 	    if(ski) { OPENSSL_free(ski); }
233 	}
234 
235 	/* Step 9: add extensions to the PKCS#10 structure */
236 	if(!X509_REQ_add_extensions(xreq, exts)) {
237 	    P_ERR();
238 	    goto err;
239 	}
240     }
241 
242     /* step 10: sign PKCS#10 */
243     const EVP_MD *md = EVP_get_digestbynid(X509_REQ_get_signature_nid(xreq));
244     if(!X509_REQ_sign(xreq, pk, md)) {
245 	P_ERR();
246 	goto err;
247     }
248 
249     retval = true;
250 
251 err:
252     /* cleanup */
253     if(exts != NULL) { sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); exts=NULL; }    if(name != NULL) { X509_NAME_free(name); }
254     /* memory management */
255 
256     return retval;
257 }
258 
259 
260 /* EOF */
261