1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** NetX Secure Component                                                 */
17 /**                                                                       */
18 /**    X.509 Digital Certificates                                         */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_SECURE_SOURCE_CODE
24 
25 #include "nx_secure_x509.h"
26 
27 /**************************************************************************/
28 /*                                                                        */
29 /*  FUNCTION                                               RELEASE        */
30 /*                                                                        */
31 /*    _nx_secure_x509_certificate_chain_verify            PORTABLE C      */
32 /*                                                           6.1.12       */
33 /*  AUTHOR                                                                */
34 /*                                                                        */
35 /*    Timothy Stapko, Microsoft Corporation                               */
36 /*                                                                        */
37 /*  DESCRIPTION                                                           */
38 /*                                                                        */
39 /*    This function verifies a certificate chain (built using the service */
40 /*    nx_secure_certificate_chain_build) by checking each issuer back to  */
41 /*    a certificate in the trusted store of the given X509 store.         */
42 /*                                                                        */
43 /*  INPUT                                                                 */
44 /*                                                                        */
45 /*    store                                 Pointer to certificate store  */
46 /*    certificate                           Pointer to cert chain         */
47 /*                                                                        */
48 /*  OUTPUT                                                                */
49 /*                                                                        */
50 /*    status                                Completion status             */
51 /*                                                                        */
52 /*  CALLS                                                                 */
53 /*                                                                        */
54 /*    _nx_secure_x509_certificate_verify    Verify a certificate          */
55 /*    _nx_secure_x509_store_certificate_find                              */
56 /*                                          Find a cert in a store        */
57 /*    _nx_secure_x509_distinguished_name_compare                          */
58 /*                                          Compare distinguished name    */
59 /*                                                                        */
60 /*  CALLED BY                                                             */
61 /*                                                                        */
62 /*    _nx_secure_tls_remote_certificate_verify                            */
63 /*                                          Verify the server certificate */
64 /*    _nx_secure_x509_crl_revocation_check  Check revocation in crl       */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
71 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*  04-02-2021     Timothy Stapko           Modified comment(s),          */
74 /*                                            removed dependency on TLS,  */
75 /*                                            resulting in version 6.1.6  */
76 /*  04-25-2022     Yuxin Zhou               Modified comment(s), and      */
77 /*                                            reorganized internal logic, */
78 /*                                            resulting in version 6.1.11 */
79 /*  07-29-2022     Yuxin Zhou               Modified comment(s), and      */
80 /*                                            checked expiration for all  */
81 /*                                            the certs in the chain,     */
82 /*                                            resulting in version 6.1.12 */
83 /*                                                                        */
84 /**************************************************************************/
_nx_secure_x509_certificate_chain_verify(NX_SECURE_X509_CERTIFICATE_STORE * store,NX_SECURE_X509_CERT * certificate,ULONG current_time)85 UINT _nx_secure_x509_certificate_chain_verify(NX_SECURE_X509_CERTIFICATE_STORE *store,
86                                               NX_SECURE_X509_CERT *certificate, ULONG current_time)
87 {
88 UINT                 status;
89 NX_SECURE_X509_CERT *current_certificate;
90 NX_SECURE_X509_CERT *issuer_certificate;
91 UINT                 issuer_location = NX_SECURE_X509_CERT_LOCATION_NONE;
92 INT                  compare_result;
93 
94     /* Process, following X509 basic certificate authentication (RFC 5280):
95      *    1. Last certificate in chain is the end entity - start with it.
96      *    2. Build chain from issuer to issuer - linked list of issuers. Find in stores: [ Remote, Trusted ]
97      *    3. Walk list from end certificate back to a root CA in the trusted store, verifying each signature.
98      *       Additionally, any policy enforcement should be done at each step.
99      */
100 
101     /* Get working pointer to certificate chain entry. */
102     current_certificate = certificate;
103 
104     while (current_certificate != NX_CRYPTO_NULL)
105     {
106 
107         /* Check the certificate expiration against the current time. */
108         if (current_time != 0)
109         {
110             status = _nx_secure_x509_expiration_check(current_certificate, current_time);
111 
112             if (status != NX_SECURE_X509_SUCCESS)
113             {
114                 return(status);
115             }
116         }
117 
118         /* See if the certificate is self-signed or not. */
119         compare_result = _nx_secure_x509_distinguished_name_compare(&current_certificate -> nx_secure_x509_distinguished_name,
120                                                                     &current_certificate -> nx_secure_x509_issuer, NX_SECURE_X509_NAME_ALL_FIELDS);
121 
122         if (compare_result != 0)
123         {
124             /* Find the certificate issuer in the store. */
125             status = _nx_secure_x509_store_certificate_find(store, &current_certificate -> nx_secure_x509_issuer, 0, &issuer_certificate, &issuer_location);
126 
127             if (status != NX_SECURE_X509_SUCCESS)
128             {
129                 return(NX_SECURE_X509_ISSUER_CERTIFICATE_NOT_FOUND);
130             }
131         }
132         else
133         {
134 #ifndef NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES
135             /* The certificate is self-signed. If we don't allow that, return error. */
136             return(NX_SECURE_X509_INVALID_SELF_SIGNED_CERT);
137 #else
138             /* Certificate is self-signed and we are configured to accept them. */
139             issuer_certificate = current_certificate;
140 #endif
141         }
142 
143         /* Verify the current certificate against its issuer certificate. */
144         status = _nx_secure_x509_certificate_verify(store, current_certificate, issuer_certificate);
145 
146         if (status != 0)
147         {
148             return(status);
149         }
150         else
151         {
152             /* The comparison passed, so we have a valid issuer. If the issuer is in the trusted
153                store, our chain verification is complete. If the issuer is not in the trusted store,
154                then continue the verification process. */
155             if (issuer_location == NX_SECURE_X509_CERT_LOCATION_TRUSTED)
156             {
157                 return(NX_SECURE_X509_SUCCESS);
158             }
159 
160 #ifdef NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES
161             /* Certificate is self-signed and we are configured to accept them. */
162             if (issuer_certificate == current_certificate)
163             {
164                 /* Check for self-signed certificate in trusted store. */
165                 status = _nx_secure_x509_store_certificate_find(store, &current_certificate -> nx_secure_x509_distinguished_name, 0, &issuer_certificate, &issuer_location);
166 
167                 if(status == NX_SECURE_X509_SUCCESS && issuer_location == NX_SECURE_X509_CERT_LOCATION_TRUSTED)
168                 {
169                     return(NX_SECURE_X509_SUCCESS);
170                 }
171                 /* Self-signed certificate is not trusted. */
172                 break;
173             }
174 #endif
175         }
176 
177         /* Advance our working pointer to the next entry in the list. */
178         current_certificate = issuer_certificate;
179     } /* End while. */
180 
181     /* Certificate is invalid. */
182     return(NX_SECURE_X509_CHAIN_VERIFY_FAILURE);
183 }
184 
185