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