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