1 /* -*- mode: c; c-file-style:"stroustrup"; -*- */
2 
3 /*
4  * Copyright (c) 2020 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 #include <config.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #include <openssl/rsa.h>
24 #include <openssl/err.h>
25 #include <openssl/evp.h>
26 
27 #include "pkcs11lib.h"
28 #include "pkcs11_ossl.h"
29 
30 typedef struct {
31     pkcs11Context *p11Context;
32     CK_OBJECT_HANDLE hPrivateKey;
33     bool fake;			/* set when we don't really want to sign */
34 } local_rsa_method_st ;
35 
36 
37 static local_rsa_method_st static_st; /* TODO use CTRL API to make reentrant */
38 
39 
40 static int (*orig_rsa_sign) (EVP_PKEY_CTX *ctx,
41 			     unsigned char *sig, size_t *siglen,
42 			     const unsigned char *tbs, size_t tbslen) = NULL;
43 
44 
45 
custom_rsa_sign(EVP_PKEY_CTX * ctx,unsigned char * sig,size_t * siglen,const unsigned char * tbs,size_t tbslen)46 static int custom_rsa_sign( EVP_PKEY_CTX *ctx,
47 			    unsigned char *sig,
48 			    size_t *siglen,
49 			    const unsigned char *tbs,
50 			    size_t tbslen) {
51 
52     static bool entered = false;
53     /* if entered is true, this means we are calling a PKCS#11 implementation */
54     /* that uses also OpenSSL, which is also using the same EVP methods as us */
55     /* In which case, we call the original method  (before customization)     */
56     /* otherwise we would enter an endless recursion...                       */
57     /* NOTE: this mechanism is NOT thread-safe                                */
58 
59     if( entered==true ) {
60 	return orig_rsa_sign(ctx, sig, siglen, tbs, tbslen);
61     } else {
62 	entered = true;		/* set entered state */
63 	/* TODO: check if static_st is populated */
64 
65 	int rc = 0;
66 	CK_RV rv;
67 	const EVP_MD *md;
68 	uint8_t digestinfo[19+64];	/* the longest supported is SHA512 */
69 
70 	/* TODO: change this to dynamic build of the object */
71 	static const uint8_t header_sha1[] = {
72 	    0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
73 	    0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
74 	};
75 
76 	static const uint8_t header_sha224[] = {
77 	    0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
78 	    0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
79 	    0x00, 0x04, 0x1c
80 	};
81 
82 	static const uint8_t header_sha256[] = {
83 	    0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
84 	    0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
85 	    0x00, 0x04, 0x20
86 	};
87 
88 	static const uint8_t header_sha384[] = {
89 	    0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
90 	    0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
91 	    0x00, 0x04, 0x30
92 	};
93 
94 	static const uint8_t header_sha512[] = {
95 	    0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
96 	    0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
97 	    0x00, 0x04, 0x30
98 	};
99 
100 	typedef struct {
101 	    const unsigned int nid;
102 	    const uint8_t * header;
103 	    const size_t len;
104 	} hash_header_map_st;
105 
106 	static const hash_header_map_st hash_header_map[] = {
107 	    { NID_sha1, header_sha1, sizeof header_sha1 / sizeof(uint8_t) },
108 	    { NID_sha224, header_sha224, sizeof header_sha224 / sizeof(uint8_t) },
109 	    { NID_sha256, header_sha256, sizeof header_sha256 / sizeof(uint8_t) },
110 	    { NID_sha384, header_sha384, sizeof header_sha384 / sizeof(uint8_t) },
111 	    { NID_sha512, header_sha512, sizeof header_sha512 / sizeof(uint8_t) },
112 	};
113 
114 	CK_MECHANISM mechanism = { CKM_RSA_PKCS, NULL_PTR, 0 };
115 
116 	if(!static_st.fake) {
117 	    rv = static_st.p11Context->FunctionList.C_SignInit( static_st.p11Context->Session,
118 								&mechanism,
119 								static_st.hPrivateKey);
120 	    if(rv!= CKR_OK) {
121 		pkcs11_error(rv,"C_SignInit");
122 		goto err;
123 	    }
124 	}
125 
126 	if(EVP_PKEY_CTX_get_signature_md(ctx, &md)<=0) {
127 	    P_ERR();
128 	    goto err;
129 	}
130 
131 	/* because CKM_RSA_PKCS is unaware of the hash algorithm, */
132 	/* we have to feed the DigestInfo ASN.1 structure,        */
133 	/* as found in RFC8017 section 9.2                        */
134 
135 	/* step 1: retrieve the proper header, by matching hash alg */
136 	int i;
137 
138 	for(i=0; i<sizeof hash_header_map / sizeof(hash_header_map_st); i++) {
139 	    if(EVP_MD_type(md) == hash_header_map[i].nid) {
140 		break;
141 	    }
142 	}
143 
144 	if(i==sizeof hash_header_map / sizeof(hash_header_map_st)) {
145 	    /* not found */
146 	    fprintf(stderr, "***Error, unsupported hashing algorithm\n");
147 	    goto err;
148 	}
149 
150 	/* step 2: copy the header to the digestinfo */
151 	memcpy(&digestinfo[0], hash_header_map[i].header, hash_header_map[i].len);
152 
153 	/* step 3: append the data to be signed after the header */
154 	memcpy(&digestinfo[hash_header_map[i].len], tbs, tbslen);
155 
156 	/* step 4: perform signature */
157 	if(static_st.fake) {
158 	    /* the buffer that offered to us is in fact oversized, to support DER encoding supplement bytes */
159 	    /* when invoking C_Sign(), p11siglen gets adjusted to the real value                            */
160 	    /* we have to do the same for fake_sign: we must also adjust p11siglen,                         */
161 	    /* so we can encapsulate the fake signature accordingly                                         */
162 	    const RSA *rsa = EVP_PKEY_get0_RSA(EVP_PKEY_CTX_get0_pkey(ctx)); /* TODO error checking */
163 	    const BIGNUM *rsa_n = RSA_get0_n(rsa);
164 	    *siglen = BN_num_bytes(rsa_n); /* the signature size is the size of the modulus */
165 	    fake_sign(sig,*siglen);
166 	} else {
167 	    rv = static_st.p11Context->FunctionList.C_Sign(static_st.p11Context->Session,
168 							   (CK_BYTE_PTR)digestinfo,
169 							   hash_header_map[i].len + EVP_MD_size(md),
170 							   sig,
171 							   (CK_ULONG_PTR)siglen);
172 
173 	    if(rv!= CKR_OK) {
174 		pkcs11_error(rv,"C_Sign");
175 		goto err;
176 	    }
177 	}
178 	rc = 1;
179 
180     err:
181 	entered = false;
182 	return rc;
183     }
184 }
185 
186 
pkcs11_rsa_method_setup()187 void pkcs11_rsa_method_setup()
188 {
189     const EVP_PKEY_METHOD *orig_rsamethod;
190     EVP_PKEY_METHOD *custom_rsamethod;
191 
192     /* customizing signing methods */
193     /* we are doing SHA1 / RSA signing */
194     orig_rsamethod = EVP_PKEY_meth_find(EVP_PKEY_RSA);
195     if(orig_rsamethod==NULL) {
196 	ERR_print_errors_fp(stderr);
197 	exit(1);		/* TODO CHANGE THIS */
198     }
199 
200     /* create a new EVP_PKEY_METHOD */
201     custom_rsamethod = EVP_PKEY_meth_new( EVP_PKEY_RSA, EVP_PKEY_FLAG_AUTOARGLEN);
202     if(custom_rsamethod==NULL) {
203 	ERR_print_errors_fp(stderr);
204 	exit(1);
205     }
206 
207     /* copy all from the EVP_PKEY_METHOD we want to customize */
208     EVP_PKEY_meth_copy( custom_rsamethod, orig_rsamethod);
209 
210     /* For the calls we want to tweak, recover the original fn pointers */
211     int (*orig_rsa_sign_init) (EVP_PKEY_CTX *ctx);
212 
213     EVP_PKEY_meth_get_sign(orig_rsamethod,
214 			   &orig_rsa_sign_init,
215 			   &orig_rsa_sign );
216 
217     /* then adapt what we want to, in this case only the sign() fn */
218 
219     EVP_PKEY_meth_set_sign(custom_rsamethod,
220 			   orig_rsa_sign_init, /* duplicate it, we don't change it */
221 			   custom_rsa_sign ); /* the new, customized method */
222 
223     EVP_PKEY_meth_add0(custom_rsamethod);
224     custom_rsamethod = NULL;	/* swallowed by EVP_PKEY_meth_add0 */
225 }
226 
227 
pkcs11_rsa_method_pkcs11_context(pkcs11Context * p11Context,CK_OBJECT_HANDLE hPrivateKey,bool fake)228 void pkcs11_rsa_method_pkcs11_context(pkcs11Context * p11Context, CK_OBJECT_HANDLE hPrivateKey, bool fake)
229 {
230     static_st.p11Context = p11Context;
231     static_st.hPrivateKey = hPrivateKey;
232     static_st.fake = fake;
233 }
234