1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Secure Component */
16 /** */
17 /** X.509 Digital Certificates */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SECURE_SOURCE_CODE
23
24 #include "nx_secure_x509.h"
25
26 static UCHAR generated_hash[64]; /* We need to be able to hold the entire generated hash - SHA-512 = 64 bytes. */
27 static UCHAR decrypted_signature[512]; /* This needs to hold the entire decrypted data - RSA 2048-bit key = 256 bytes. */
28
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_secure_x509_certificate_verify PORTABLE C */
36 /* 6.1.11 */
37 /* AUTHOR */
38 /* */
39 /* Timothy Stapko, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function verifies a certificate by checking its signature */
44 /* against its issuer's public key. */
45 /* */
46 /* INPUT */
47 /* */
48 /* store Pointer to certificate store */
49 /* certificate Pointer to certificate */
50 /* issuer_certificate Pointer to issuer certificate */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* status Completion status */
55 /* */
56 /* CALLS */
57 /* */
58 /* [nx_crypto_init] Crypto initialization */
59 /* [nx_crypto_operation] Crypto operation */
60 /* _nx_secure_x509_pkcs7_decode Decode the PKCS#7 signature */
61 /* _nx_secure_x509_find_certificate_methods */
62 /* Find certificate methods */
63 /* _nx_secure_x509_find_curve_method Find named curve used */
64 /* _nx_secure_x509_asn1_tlv_block_parse Parse ASN.1 block */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* _nx_secure_x509_certificate_chain_verify */
69 /* Verify cert against stores */
70 /* */
71 /* RELEASE HISTORY */
72 /* */
73 /* DATE NAME DESCRIPTION */
74 /* */
75 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
76 /* 09-30-2020 Timothy Stapko Modified comment(s), update */
77 /* ECC find curve method, */
78 /* add KeyUsage check, */
79 /* resulting in version 6.1 */
80 /* 04-02-2021 Timothy Stapko Modified comment(s), */
81 /* removed dependency on TLS, */
82 /* resulting in version 6.1.6 */
83 /* 04-25-2022 Yuxin Zhou Modified comment(s), */
84 /* removed unnecessary code, */
85 /* resulting in version 6.1.11 */
86 /* */
87 /**************************************************************************/
_nx_secure_x509_certificate_verify(NX_SECURE_X509_CERTIFICATE_STORE * store,NX_SECURE_X509_CERT * certificate,NX_SECURE_X509_CERT * issuer_certificate)88 UINT _nx_secure_x509_certificate_verify(NX_SECURE_X509_CERTIFICATE_STORE *store,
89 NX_SECURE_X509_CERT *certificate,
90 NX_SECURE_X509_CERT *issuer_certificate)
91 {
92 UINT status;
93 UINT oid_length;
94 const UCHAR *oid;
95 UINT decrypted_hash_length;
96 const UCHAR *decrypted_hash;
97 const UCHAR *certificate_verify_data;
98 UINT verify_data_length;
99 const UCHAR *signature_data;
100 UINT signature_length;
101 UINT compare_result;
102 UINT hash_length;
103 const NX_CRYPTO_METHOD *hash_method;
104 const NX_CRYPTO_METHOD *public_cipher_method;
105 NX_SECURE_X509_CRYPTO *crypto_methods;
106 VOID *handler = NX_CRYPTO_NULL;
107 #ifndef NX_SECURE_X509_DISABLE_KEY_USAGE_CHECK
108 USHORT key_usage_bitfield = 0;
109 #endif
110 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
111 NX_SECURE_EC_PUBLIC_KEY *ec_pubkey;
112 const NX_CRYPTO_METHOD *curve_method;
113 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
114
115 NX_CRYPTO_PARAMETER_NOT_USED(store);
116
117 #ifndef NX_SECURE_X509_DISABLE_KEY_USAGE_CHECK
118 /* Before we do any crypto verification, we need to check the KeyUsage extension. */
119 status = _nx_secure_x509_key_usage_extension_parse(issuer_certificate, &key_usage_bitfield);
120
121 /* If extension is not present, we don't need to verify per RFC 5280. */
122 if(NX_SECURE_X509_SUCCESS == status)
123 {
124 /* The issuer cert has a KeyUsage extension - check the KeyCertSign bit. */
125 if(!(key_usage_bitfield & NX_SECURE_X509_KEY_USAGE_KEY_CERT_SIGN))
126 {
127 return(NX_SECURE_X509_KEY_USAGE_ERROR);
128 }
129 }
130 #endif
131
132 /* Get working pointers to relevant data. */
133 certificate_verify_data = certificate -> nx_secure_x509_certificate_data;
134 verify_data_length = certificate -> nx_secure_x509_certificate_data_length;
135 signature_data = certificate -> nx_secure_x509_signature_data;
136 signature_length = certificate -> nx_secure_x509_signature_data_length;
137
138 /* Find certificate crypto methods for this certificate. */
139 status = _nx_secure_x509_find_certificate_methods(certificate, (USHORT)certificate -> nx_secure_x509_signature_algorithm, &crypto_methods);
140 if (status != NX_SECURE_X509_SUCCESS)
141 {
142 return(status);
143 }
144
145 /* Assign local pointers for the crypto methods. */
146 hash_method = crypto_methods -> nx_secure_x509_hash_method;
147 public_cipher_method = crypto_methods -> nx_secure_x509_public_cipher_method;
148
149 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
150 NX_SECURE_MEMSET(decrypted_signature, 0, sizeof(decrypted_signature));
151
152 if (hash_method -> nx_crypto_init)
153 {
154 status = hash_method -> nx_crypto_init((NX_CRYPTO_METHOD*)hash_method,
155 NX_CRYPTO_NULL,
156 0,
157 &handler,
158 certificate -> nx_secure_x509_hash_metadata_area,
159 certificate -> nx_secure_x509_hash_metadata_size);
160
161 if(status != NX_CRYPTO_SUCCESS)
162 {
163 return(status);
164 }
165 }
166
167 /* We need to generate a hash of this certificate in order to verify it against our trusted store. */
168 if (hash_method -> nx_crypto_operation != NX_CRYPTO_NULL)
169 {
170 status = hash_method -> nx_crypto_operation(NX_CRYPTO_VERIFY,
171 handler,
172 (NX_CRYPTO_METHOD*)hash_method,
173 NX_CRYPTO_NULL,
174 0,
175 (UCHAR *)certificate_verify_data,
176 verify_data_length,
177 NX_CRYPTO_NULL,
178 generated_hash,
179 sizeof(generated_hash),
180 certificate -> nx_secure_x509_hash_metadata_area,
181 certificate -> nx_secure_x509_hash_metadata_size,
182 NX_CRYPTO_NULL, NX_CRYPTO_NULL);
183
184 if(status != NX_CRYPTO_SUCCESS)
185 {
186 return(status);
187 }
188 }
189
190 if (hash_method -> nx_crypto_cleanup)
191 {
192 status = hash_method -> nx_crypto_cleanup(certificate -> nx_secure_x509_hash_metadata_area);
193
194 if(status != NX_CRYPTO_SUCCESS)
195 {
196 #ifdef NX_SECURE_KEY_CLEAR
197 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
198 #endif /* NX_SECURE_KEY_CLEAR */
199 return(status);
200 }
201 }
202
203 hash_length = (hash_method -> nx_crypto_ICV_size_in_bits >> 3);
204
205 /* Perform a public-key decryption operation on the extracted signature from the certificate.
206 * In this case, the operation is doing a "reverse decryption", using the public key to decrypt, rather
207 * than the private. This allows us to tie a trusted root certificate to a signature of a certificate
208 * signed by that root CA's private key. when combined with a hash method, this is the basic digital
209 * signature operation. */
210 if (public_cipher_method -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_RSA ||
211 public_cipher_method -> nx_crypto_algorithm == NX_CRYPTO_DIGITAL_SIGNATURE_RSA)
212 {
213 /* Make sure the public algorithm of the issuer certificate is RSA. */
214 if (issuer_certificate -> nx_secure_x509_public_algorithm != NX_SECURE_TLS_X509_TYPE_RSA)
215 {
216 #ifdef NX_SECURE_KEY_CLEAR
217 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
218 #endif /* NX_SECURE_KEY_CLEAR */
219
220 return(NX_SECURE_X509_WRONG_SIGNATURE_METHOD);
221 }
222
223 if (public_cipher_method -> nx_crypto_init != NX_CRYPTO_NULL)
224 {
225 /* Initialize the crypto method with public key. */
226 status = public_cipher_method -> nx_crypto_init((NX_CRYPTO_METHOD*)public_cipher_method,
227 (UCHAR *)issuer_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_modulus,
228 (NX_CRYPTO_KEY_SIZE)(issuer_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_modulus_length << 3),
229 &handler,
230 certificate -> nx_secure_x509_public_cipher_metadata_area,
231 certificate -> nx_secure_x509_public_cipher_metadata_size);
232
233 if(status != NX_CRYPTO_SUCCESS)
234 {
235 #ifdef NX_SECURE_KEY_CLEAR
236 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
237 #endif /* NX_SECURE_KEY_CLEAR */
238
239 return(status);
240 }
241 }
242
243 if (public_cipher_method -> nx_crypto_operation != NX_CRYPTO_NULL)
244 {
245 status = public_cipher_method -> nx_crypto_operation(NX_CRYPTO_DECRYPT,
246 handler,
247 (NX_CRYPTO_METHOD*)public_cipher_method,
248 (UCHAR *)issuer_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_exponent,
249 (NX_CRYPTO_KEY_SIZE)(issuer_certificate -> nx_secure_x509_public_key.rsa_public_key.nx_secure_rsa_public_exponent_length << 3),
250 (UCHAR *)signature_data,
251 signature_length,
252 NX_CRYPTO_NULL,
253 decrypted_signature,
254 sizeof(decrypted_signature),
255 certificate -> nx_secure_x509_public_cipher_metadata_area,
256 certificate -> nx_secure_x509_public_cipher_metadata_size,
257 NX_CRYPTO_NULL, NX_CRYPTO_NULL);
258
259 if(status != NX_CRYPTO_SUCCESS)
260 {
261 #ifdef NX_SECURE_KEY_CLEAR
262 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
263 #endif /* NX_SECURE_KEY_CLEAR */
264
265 return(status);
266 }
267 }
268
269 if (public_cipher_method -> nx_crypto_cleanup)
270 {
271 status = public_cipher_method -> nx_crypto_cleanup(certificate -> nx_secure_x509_public_cipher_metadata_area);
272
273 if(status != NX_CRYPTO_SUCCESS)
274 {
275 #ifdef NX_SECURE_KEY_CLEAR
276 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
277 NX_SECURE_MEMSET(decrypted_signature, 0, sizeof(decrypted_signature));
278 #endif /* NX_SECURE_KEY_CLEAR */
279
280 return(status);
281 }
282 }
283
284 /* Decode the decrypted signature, which should be in PKCS#7 format. */
285 status = _nx_secure_x509_pkcs7_decode(decrypted_signature, signature_length, &oid, &oid_length,
286 &decrypted_hash, &decrypted_hash_length);
287
288 #ifdef NX_SECURE_KEY_CLEAR
289 if(status != NX_SECURE_X509_SUCCESS || decrypted_hash_length != hash_length)
290 {
291 /* Clear secrets state on errors. */
292 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
293 NX_SECURE_MEMSET(decrypted_signature, 0, sizeof(decrypted_signature));
294 }
295 #endif /* NX_SECURE_KEY_CLEAR */
296
297 if (status != NX_SECURE_X509_SUCCESS)
298 {
299 return(status);
300 }
301
302 if (decrypted_hash_length != hash_length)
303 {
304 return(NX_SECURE_X509_WRONG_SIGNATURE_METHOD);
305 }
306
307 /* Compare generated hash with decrypted hash. */
308 compare_result = (UINT)NX_SECURE_MEMCMP(generated_hash, decrypted_hash, decrypted_hash_length);
309
310 #ifdef NX_SECURE_KEY_CLEAR
311 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
312 NX_SECURE_MEMSET(decrypted_signature, 0, sizeof(decrypted_signature));
313 #endif /* NX_SECURE_KEY_CLEAR */
314
315 /* If the comparision worked, return success. */
316 if (compare_result == 0)
317 {
318 return(NX_SECURE_X509_SUCCESS);
319 }
320 }
321 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
322 else if (public_cipher_method -> nx_crypto_algorithm == NX_CRYPTO_DIGITAL_SIGNATURE_ECDSA)
323 {
324 /* Make sure the public algorithm of the issuer certificate is EC. */
325 if (issuer_certificate -> nx_secure_x509_public_algorithm != NX_SECURE_TLS_X509_TYPE_EC)
326 {
327 return(NX_SECURE_X509_WRONG_SIGNATURE_METHOD);
328 }
329
330 /* Verify the ECDSA signature. */
331
332 ec_pubkey = &issuer_certificate -> nx_secure_x509_public_key.ec_public_key;
333
334 /* Find out which named curve the remote certificate is using. */
335 status = _nx_secure_x509_find_curve_method((USHORT)(ec_pubkey -> nx_secure_ec_named_curve), &curve_method);
336
337 #ifdef NX_SECURE_KEY_CLEAR
338 if(status != NX_SECURE_X509_SUCCESS || curve_method == NX_CRYPTO_NULL)
339 {
340 /* Clear secrets on errors. */
341 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
342 }
343 #endif /* NX_SECURE_KEY_CLEAR */
344
345
346 if(status != NX_SECURE_X509_SUCCESS)
347 {
348 return(status);
349 }
350
351 if (public_cipher_method -> nx_crypto_init != NX_CRYPTO_NULL)
352 {
353 status = public_cipher_method -> nx_crypto_init((NX_CRYPTO_METHOD*)public_cipher_method,
354 (UCHAR *)ec_pubkey -> nx_secure_ec_public_key,
355 (NX_CRYPTO_KEY_SIZE)(ec_pubkey -> nx_secure_ec_public_key_length << 3),
356 &handler,
357 certificate -> nx_secure_x509_public_cipher_metadata_area,
358 certificate -> nx_secure_x509_public_cipher_metadata_size);
359 if (status != NX_CRYPTO_SUCCESS)
360 {
361 #ifdef NX_SECURE_KEY_CLEAR
362 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
363 #endif /* NX_SECURE_KEY_CLEAR */
364
365 return(status);
366 }
367 }
368 if (public_cipher_method -> nx_crypto_operation == NX_CRYPTO_NULL)
369 {
370 #ifdef NX_SECURE_KEY_CLEAR
371 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
372 #endif /* NX_SECURE_KEY_CLEAR */
373
374 return(NX_SECURE_X509_MISSING_CRYPTO_ROUTINE);
375 }
376
377 status = public_cipher_method -> nx_crypto_operation(NX_CRYPTO_EC_CURVE_SET, handler,
378 (NX_CRYPTO_METHOD*)public_cipher_method, NX_CRYPTO_NULL, 0,
379 (UCHAR *)curve_method, sizeof(NX_CRYPTO_METHOD *), NX_CRYPTO_NULL,
380 NX_CRYPTO_NULL, 0,
381 certificate -> nx_secure_x509_public_cipher_metadata_area,
382 certificate -> nx_secure_x509_public_cipher_metadata_size,
383 NX_CRYPTO_NULL, NX_CRYPTO_NULL);
384 if (status != NX_CRYPTO_SUCCESS)
385 {
386 #ifdef NX_SECURE_KEY_CLEAR
387 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
388 #endif /* NX_SECURE_KEY_CLEAR */
389
390 return(status);
391 }
392
393 status = public_cipher_method -> nx_crypto_operation(NX_CRYPTO_VERIFY, handler,
394 (NX_CRYPTO_METHOD*)public_cipher_method,
395 (UCHAR *)ec_pubkey -> nx_secure_ec_public_key,
396 (NX_CRYPTO_KEY_SIZE)(ec_pubkey -> nx_secure_ec_public_key_length << 3),
397 generated_hash,
398 hash_method -> nx_crypto_ICV_size_in_bits >> 3,
399 NX_CRYPTO_NULL,
400 (UCHAR *)signature_data,
401 signature_length,
402 certificate -> nx_secure_x509_public_cipher_metadata_area,
403 certificate -> nx_secure_x509_public_cipher_metadata_size,
404 NX_CRYPTO_NULL, NX_CRYPTO_NULL);
405 #ifdef NX_SECURE_KEY_CLEAR
406 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
407 #endif /* NX_SECURE_KEY_CLEAR */
408
409 if (status == NX_CRYPTO_SUCCESS)
410 {
411 return(NX_SECURE_X509_SUCCESS);
412 }
413 }
414 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
415 else
416 {
417 return(NX_SECURE_X509_UNSUPPORTED_PUBLIC_CIPHER);
418 }
419
420 #ifdef NX_SECURE_KEY_CLEAR
421 NX_SECURE_MEMSET(generated_hash, 0, sizeof(generated_hash));
422 #endif /* NX_SECURE_KEY_CLEAR */
423
424 /* Comparison failed, return error. */
425 return(NX_SECURE_X509_CERTIFICATE_SIG_CHECK_FAILED);
426 }
427
428