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