1 /*
2 * Copyright 2021 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <libcr51sign/libcr51sign_support.h>
18 #include <openssl/bio.h>
19 #include <openssl/bn.h>
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/pem.h>
23 #include <openssl/rsa.h>
24 #include <openssl/sha.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #ifdef __cplusplus
30 extern "C"
31 {
32 #endif
33
34 #ifndef USER_PRINT
35 #define CPRINTS(ctx, ...) fprintf(stderr, __VA_ARGS__)
36 #endif
37
38 // @func hash_init get ready to compute a hash
39 //
40 // @param[in] ctx - context struct
41 // @param[in] hash_type - type of hash function to use
42 //
43 // @return nonzero on error, zero on success
44
hash_init(const void * ctx,enum hash_type type)45 int hash_init(const void* ctx, enum hash_type type)
46 {
47 struct libcr51sign_ctx* context = (struct libcr51sign_ctx*)ctx;
48 struct hash_ctx* hash_context = (struct hash_ctx*)context->priv;
49 hash_context->hash_type = type;
50 if (type == HASH_SHA2_256)
51 { // SHA256_Init returns 1
52 SHA256_Init(&hash_context->sha256_ctx);
53 }
54 else if (type == HASH_SHA2_512)
55 {
56 SHA512_Init(&hash_context->sha512_ctx);
57 }
58 else
59 {
60 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
61 }
62
63 return LIBCR51SIGN_SUCCESS;
64 }
65
66 // @func hash_update add data to the hash
67 //
68 // @param[in] ctx - context struct
69 // @param[in] buf - data to add to hash
70 // @param[in] count - number of bytes of data to add
71 //
72 // @return nonzero on error, zero on success
73
hash_update(void * ctx,const uint8_t * data,size_t size)74 int hash_update(void* ctx, const uint8_t* data, size_t size)
75 {
76 if (size == 0)
77 return LIBCR51SIGN_SUCCESS;
78 struct libcr51sign_ctx* context = (struct libcr51sign_ctx*)ctx;
79 struct hash_ctx* hash_context = (struct hash_ctx*)context->priv;
80
81 if (hash_context->hash_type == HASH_SHA2_256)
82 { // SHA256_Update returns 1
83 SHA256_Update(&hash_context->sha256_ctx, data, size);
84 }
85 else if (hash_context->hash_type == HASH_SHA2_512)
86 {
87 SHA512_Update(&hash_context->sha512_ctx, data, size);
88 }
89 else
90 {
91 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
92 }
93
94 return LIBCR51SIGN_SUCCESS;
95 }
96
97 // @func hash_final finish hash calculation
98 //
99 // @param[in] ctx - context struct
100 // @param[out] hash - buffer to write hash to (guaranteed to be big enough)
101 //
102 // @return nonzero on error, zero on success
103
hash_final(void * ctx,uint8_t * hash)104 int hash_final(void* ctx, uint8_t* hash)
105 {
106 int rv;
107 struct libcr51sign_ctx* context = (struct libcr51sign_ctx*)ctx;
108 struct hash_ctx* hash_context = (struct hash_ctx*)context->priv;
109
110 if (hash_context->hash_type == HASH_SHA2_256)
111 {
112 rv = SHA256_Final(hash, &hash_context->sha256_ctx);
113 }
114 else if (hash_context->hash_type == HASH_SHA2_512)
115 {
116 rv = SHA512_Final(hash, &hash_context->sha512_ctx);
117 }
118 else
119 {
120 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
121 }
122
123 if (rv)
124 {
125 return LIBCR51SIGN_SUCCESS;
126 }
127
128 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
129 }
130
131 // @func verify check that the signature is valid for given hashed data
132 //
133 // @param[in] ctx - context struct
134 // @param[in] scheme - type of signature, hash, etc.
135 // @param[in] sig - signature blob
136 // @param[in] sig_len - length of signature in bytes
137 // @param[in] data - pre-hashed data to verify
138 // @param[in] data_len - length of hashed data in bytes
139 //
140 // verify_signature expects RSA public key file path in ctx->key_ring
141 // @return nonzero on error, zero on success
142
verify_signature(const void * ctx,enum signature_scheme sig_scheme,const uint8_t * sig,size_t sig_len,const uint8_t * data,size_t data_len)143 int verify_signature(const void* ctx, enum signature_scheme sig_scheme,
144 const uint8_t* sig, size_t sig_len, const uint8_t* data,
145 size_t data_len)
146 {
147 // By default returns error.
148 int rv = LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
149
150 CPRINTS(ctx, "sig_len %zu sig: ", sig_len);
151 for (size_t i = 0; i < sig_len; i++)
152 {
153 CPRINTS(ctx, "%x", sig[i]);
154 }
155 CPRINTS(ctx, "\n");
156
157 struct libcr51sign_ctx* lctx = (struct libcr51sign_ctx*)ctx;
158 FILE* fp = fopen(lctx->keyring, "r");
159 RSA *rsa = NULL, *pub_rsa = NULL;
160 EVP_PKEY* pkey = NULL;
161 BIO* bio = BIO_new(BIO_s_mem());
162 if (!fp)
163 {
164 CPRINTS(ctx, "fopen failed\n");
165 goto clean_up;
166 }
167
168 pkey = PEM_read_PUBKEY(fp, 0, 0, 0);
169 if (!pkey)
170 {
171 CPRINTS(ctx, "Read public key failed\n");
172 goto clean_up;
173 }
174
175 rsa = EVP_PKEY_get1_RSA(pkey);
176 if (!rsa)
177 {
178 goto clean_up;
179 }
180 pub_rsa = RSAPublicKey_dup(rsa);
181 if (!RSA_print(bio, pub_rsa, 2))
182 {
183 CPRINTS(ctx, "RSA print failed\n");
184 }
185 if (!pub_rsa)
186 {
187 CPRINTS(ctx, "no pub RSA\n");
188 goto clean_up;
189 }
190 CPRINTS(ctx, "public RSA\n");
191 char buffer[1024] = {};
192 while (BIO_read(bio, buffer, sizeof(buffer) - 1) > 0)
193 {
194 CPRINTS(ctx, " %s", buffer);
195 }
196 enum hash_type hash_type;
197 rv = get_hash_type_from_signature(sig_scheme, &hash_type);
198 if (rv != LIBCR51SIGN_SUCCESS)
199 {
200 CPRINTS(ctx, "Invalid hash_type!\n");
201 goto clean_up;
202 }
203 int hash_nid = -1;
204 if (hash_type == HASH_SHA2_256)
205 {
206 hash_nid = NID_sha256;
207 }
208 else if (hash_type == HASH_SHA2_512)
209 {
210 hash_nid = NID_sha512;
211 }
212 else
213 {
214 rv = LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
215 goto clean_up;
216 }
217
218 int ret = RSA_verify(hash_nid, data, data_len, sig, sig_len, pub_rsa);
219 // OpenSSL RSA_verify returns 1 on success and 0 on failure
220 if (!ret)
221 {
222 CPRINTS(ctx, "OPENSSL_ERROR: %s\n",
223 ERR_error_string(ERR_get_error(), NULL));
224 rv = LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
225 goto clean_up;
226 }
227 rv = LIBCR51SIGN_SUCCESS;
228 CPRINTS(ctx, "sig: ");
229 for (size_t i = 0; i < sig_len; i++)
230 {
231 CPRINTS(ctx, "%x", sig[i]);
232 }
233 CPRINTS(ctx, "\n");
234
235 CPRINTS(ctx, "data: ");
236 for (size_t i = 0; i < data_len; i++)
237 {
238 CPRINTS(ctx, "%x", data[i]);
239 }
240 CPRINTS(ctx, "\n");
241
242 const unsigned rsa_size = RSA_size(pub_rsa);
243 CPRINTS(ctx, "rsa size %d sig_len %d\n", rsa_size, (uint32_t)sig_len);
244
245 clean_up:
246 if (fp)
247 {
248 fclose(fp);
249 }
250 EVP_PKEY_free(pkey);
251 RSA_free(rsa);
252 RSA_free(pub_rsa);
253 BIO_free(bio);
254 return rv;
255 }
256
257 // @func Verify RSA signature with modulus and exponent
258 // @param[in] ctx - context struct
259 // @param[in] sig_scheme - signature scheme
260 // @param[in] modulus - modulus of the RSA key, MSB (big-endian)
261 // @param[in] modulus_len - length of modulus in bytes
262 // @param[in] exponent - exponent of the RSA key
263 // @param[in] sig - signature blob
264 // @param[in] sig_len - length of signature in bytes
265 // @param[in] digest - digest to verify
266 // @param[in] digest_len - digest size
267 //
268 // @return true: if the signature is verified
269 // false: otherwise
verify_rsa_signature_with_modulus_and_exponent(const void * ctx,enum signature_scheme sig_scheme,const uint8_t * modulus,int modulus_len,uint32_t exponent,const uint8_t * sig,int sig_len,const uint8_t * digest,int digest_len)270 __attribute__((nonnull)) bool verify_rsa_signature_with_modulus_and_exponent(
271 const void* ctx, enum signature_scheme sig_scheme, const uint8_t* modulus,
272 int modulus_len, uint32_t exponent, const uint8_t* sig, int sig_len,
273 const uint8_t* digest, int digest_len)
274 {
275 RSA* rsa = NULL;
276 BIGNUM* n = NULL;
277 BIGNUM* e = NULL;
278 int ret = 0;
279 int hash_nid = NID_undef;
280 int expected_modulus_bits = 0;
281 int expected_digest_len = 0;
282
283 CPRINTS(ctx, "%s: sig_scheme = %d\n", __FUNCTION__, sig_scheme);
284 // Determine hash NID and expected modulus size based on signature_scheme
285 switch (sig_scheme)
286 {
287 case SIGNATURE_RSA2048_PKCS15:
288 expected_modulus_bits = 2048;
289 hash_nid = NID_sha256;
290 expected_digest_len = SHA256_DIGEST_LENGTH;
291 break;
292 case SIGNATURE_RSA3072_PKCS15:
293 expected_modulus_bits = 3072;
294 hash_nid = NID_sha256;
295 expected_digest_len = SHA256_DIGEST_LENGTH;
296 break;
297 case SIGNATURE_RSA4096_PKCS15:
298 expected_modulus_bits = 4096;
299 hash_nid = NID_sha256;
300 expected_digest_len = SHA256_DIGEST_LENGTH;
301 break;
302 case SIGNATURE_RSA4096_PKCS15_SHA512:
303 expected_modulus_bits = 4096;
304 hash_nid = NID_sha512;
305 expected_digest_len = SHA512_DIGEST_LENGTH;
306 break;
307 default:
308 CPRINTS(ctx, "%s: Unsupported signature scheme.\n", __FUNCTION__);
309 return false;
310 }
311
312 // Input validation: Check digest length
313 if (digest_len != expected_digest_len)
314 {
315 CPRINTS(
316 ctx,
317 "%s: Mismatch in expected digest length (%d) and actual (%d).\n",
318 __FUNCTION__, expected_digest_len, digest_len);
319 return false;
320 }
321
322 // 1. Create a new RSA object
323 rsa = RSA_new();
324 if (rsa == NULL)
325 {
326 CPRINTS(ctx, "%s:Error creating RSA object: %s\n", __FUNCTION__,
327 ERR_error_string(ERR_get_error(), NULL));
328 goto err;
329 }
330
331 // 2. Convert raw modulus and exponent to BIGNUMs
332 n = BN_bin2bn(modulus, modulus_len, NULL);
333 if (n == NULL)
334 {
335 CPRINTS(ctx, "%s:Error converting modulus to BIGNUM: %s\n",
336 __FUNCTION__, ERR_error_string(ERR_get_error(), NULL));
337 goto err;
338 }
339
340 e = BN_new();
341 if (e == NULL)
342 {
343 CPRINTS(ctx, "%s: Error creating BIGNUM for exponent: %s\n",
344 __FUNCTION__, ERR_error_string(ERR_get_error(), NULL));
345 goto err;
346 }
347 if (!BN_set_word(e, exponent))
348 {
349 CPRINTS(ctx, "%s: Error setting exponent word: %s\n", __FUNCTION__,
350 ERR_error_string(ERR_get_error(), NULL));
351 goto err;
352 }
353
354 // Set the public key components. RSA_set0_key takes ownership of n and e.
355 if (!RSA_set0_key(rsa, n, e, NULL))
356 { // For public key, d is NULL
357 CPRINTS(ctx, "%s: Error setting RSA key components: %s\n", __FUNCTION__,
358 ERR_error_string(ERR_get_error(), NULL));
359 goto err;
360 }
361 n = NULL; // Clear pointers to prevent double-free
362 e = NULL;
363
364 if (RSA_bits(rsa) != expected_modulus_bits)
365 {
366 CPRINTS(
367 ctx,
368 "%s: Error: RSA key size (%d bits) does not match expected size for "
369 "scheme (%d bits).\n",
370 __FUNCTION__, RSA_bits(rsa), expected_modulus_bits);
371 goto err;
372 }
373
374 // Input validation: Signature length must match modulus length
375 if (sig_len != RSA_size(rsa))
376 {
377 CPRINTS(
378 ctx,
379 "%s: Error: Signature length (%d) does not match RSA key size (%d).\n",
380 __FUNCTION__, sig_len, RSA_size(rsa));
381 goto err;
382 }
383
384 // 3. Verify the signature
385 // RSA_verify handles the decryption, PKCS#1 v1.5 padding check, and hash
386 // comparison internally.
387 CPRINTS(ctx, "%s: RSA_verify\n", __FUNCTION__);
388 CPRINTS(ctx, "%s: hash_nid %d\n", __FUNCTION__, hash_nid);
389 CPRINTS(ctx, "%s: digest_len %d, digest: \n", __FUNCTION__, digest_len);
390 for (int i = 0; i < digest_len; i++)
391 {
392 CPRINTS(ctx, "%x", digest[i]);
393 }
394 CPRINTS(ctx, "\n");
395
396 CPRINTS(ctx, "%s: sig_len %d, sig: \n", __FUNCTION__, sig_len);
397 for (int i = 0; i < sig_len; i++)
398 {
399 CPRINTS(ctx, "%x", sig[i]);
400 }
401 CPRINTS(ctx, "\n");
402
403 ret = RSA_verify(hash_nid, digest, digest_len, sig, sig_len, rsa);
404
405 if (ret == 1)
406 {
407 CPRINTS(ctx, "%s: Signature verification successful!\n", __FUNCTION__);
408 }
409 else
410 {
411 CPRINTS(ctx, "%s: Signature verification failed: %s\n", __FUNCTION__,
412 ERR_error_string(ERR_get_error(), NULL));
413 }
414
415 err:
416 RSA_free(rsa); // Frees n and e if RSA_set0_key successfully took ownership
417 BN_free(n); // Only if RSA_set0_key failed or was not called
418 BN_free(e); // Only if RSA_set0_key failed or was not called
419 return (ret == 1);
420 (void)ctx; // make compiler happy when CPRINTS is null statemenet
421 }
422
423 #ifdef __cplusplus
424 } // extern "C"
425 #endif
426