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_initialize PORTABLE C */
32 /* 6.1.7 */
33 /* AUTHOR */
34 /* */
35 /* Timothy Stapko, Microsoft Corporation */
36 /* */
37 /* DESCRIPTION */
38 /* */
39 /* This function initializes an NX_SECURE_X509_CERT */
40 /* structure with a DER-encoded X509 digital certificate, and */
41 /* in the case of a server or client local certificate, the */
42 /* associated private key. */
43 /* */
44 /* This function takes a raw data buffer as optional input. The */
45 /* buffer is used to hold the un-parsed certificate data in DER */
46 /* encoded format. If the raw_data_buffer parameter is NX_NULL, */
47 /* The certificate data is referenced directly - DO NOT change */
48 /* the certificate data after calling this function if a separate */
49 /* buffer is not used or unexpected behavior may occur. */
50 /* */
51 /* The private key is also optional. Some certificates (such as */
52 /* in the trusted store) will not have a private key. For such */
53 /* certificates the private key parameter should be passed as */
54 /* NX_NULL. */
55 /* */
56 /* The private key, if supplied, must have a private key type, which */
57 /* is defined as a 32-bit value. If the top 16 bits are non-zero, */
58 /* the value is considered user-defined and NetX Secure will perform */
59 /* no processing on the key data. If the top 16 bits are zero, the */
60 /* value defines a type known to NetX Secure that will be parsed */
61 /* accordingly. Unknown types in the known-value range will result */
62 /* in an error. No error checking will be performed on user-defined */
63 /* types. */
64 /* */
65 /* INPUT */
66 /* */
67 /* certificate Certificate structure */
68 /* certificate_data Pointer to certificate data */
69 /* length Length of certificate data */
70 /* raw_data_buffer Buffer to hold raw cert data */
71 /* buffer_size Size of raw data buffer */
72 /* private_key Pointer to private key data */
73 /* priv_len Length of private key data */
74 /* private_key_type Type of private key data */
75 /* */
76 /* OUTPUT */
77 /* */
78 /* status Completion status */
79 /* */
80 /* CALLS */
81 /* */
82 /* _nx_secure_x509_certificate_parse Extract public key data */
83 /* _nx_secure_x509_pkcs1_rsa_private_key_parse */
84 /* Parse RSA key (PKCS#1 format) */
85 /* _nx_secure_x509_ec_private_key_parse Parse EC key */
86 /* */
87 /* CALLED BY */
88 /* */
89 /* Application Code */
90 /* */
91 /* RELEASE HISTORY */
92 /* */
93 /* DATE NAME DESCRIPTION */
94 /* */
95 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
96 /* 09-30-2020 Timothy Stapko Modified comment(s), */
97 /* verified memcpy use cases, */
98 /* resulting in version 6.1 */
99 /* 03-02-2021 Timothy Stapko Modified comment(s), */
100 /* removed unnecessary mutex, */
101 /* resulting in version 6.1.5 */
102 /* 04-02-2021 Timothy Stapko Modified comment(s), */
103 /* removed dependency on TLS, */
104 /* resulting in version 6.1.6 */
105 /* 06-02-2021 Timothy Stapko Modified comment(s), */
106 /* supported hardware EC */
107 /* private key, */
108 /* resulting in version 6.1.7 */
109 /* */
110 /**************************************************************************/
_nx_secure_x509_certificate_initialize(NX_SECURE_X509_CERT * certificate,UCHAR * certificate_data,USHORT length,UCHAR * raw_data_buffer,USHORT buffer_size,const UCHAR * private_key,USHORT priv_len,UINT private_key_type)111 UINT _nx_secure_x509_certificate_initialize(NX_SECURE_X509_CERT *certificate,
112 UCHAR *certificate_data, USHORT length,
113 UCHAR *raw_data_buffer, USHORT buffer_size,
114 const UCHAR *private_key, USHORT priv_len,
115 UINT private_key_type)
116
117 {
118 UINT status;
119 UINT bytes_processed;
120 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
121 NX_SECURE_EC_PRIVATE_KEY *ec_key;
122 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
123
124 NX_SECURE_MEMSET(certificate, 0, sizeof(NX_SECURE_X509_CERT));
125
126 /* Set up the certificate with raw data. */
127 certificate -> nx_secure_x509_certificate_raw_data_length = length;
128 if (raw_data_buffer == NX_CRYPTO_NULL)
129 {
130 /* No buffer was passed in so just point to the certificate itself. */
131 certificate -> nx_secure_x509_certificate_raw_buffer_size = length;
132 certificate -> nx_secure_x509_certificate_raw_data = certificate_data;
133 }
134 else
135 {
136 /* Make sure we have enough space in the buffer for the certificate. */
137 if (length > buffer_size)
138 {
139 return(NX_SECURE_X509_INSUFFICIENT_CERT_SPACE);
140 }
141 /* Use the caller-supplied buffer for the certificate. */
142 certificate -> nx_secure_x509_certificate_raw_buffer_size = buffer_size;
143 certificate -> nx_secure_x509_certificate_raw_data = raw_data_buffer;
144 NX_SECURE_MEMCPY(certificate -> nx_secure_x509_certificate_raw_data, certificate_data, length); /* Use case of memcpy is verified. lgtm[cpp/banned-api-usage-required-any] */
145 }
146
147 /* Parse the DER-encoded X509 certificate to extract the public key data.
148 * NOTE: All the pointers returned in the X509 cert will point into the certificate data
149 * passed in here, so DO NOT modify the certificate data or pass in a pointer to a
150 * temporary buffer!*/
151
152 status = _nx_secure_x509_certificate_parse(certificate -> nx_secure_x509_certificate_raw_data,
153 length, &bytes_processed, certificate);
154
155 if (status != 0)
156 {
157 return(NX_SECURE_X509_INVALID_CERTIFICATE);
158 }
159
160 /* If the optional private key is supplied, save it for later use. */
161 if (private_key != NULL && priv_len > 0)
162 {
163 /* Save the key type for later. */
164 certificate -> nx_secure_x509_private_key_type = private_key_type;
165
166 /* Check for user-defined key types. */
167 if ((private_key_type & NX_SECURE_X509_KEY_TYPE_USER_DEFINED_MASK) != 0x0)
168 {
169 /* User-defined, just save off the key data. */
170 certificate -> nx_secure_x509_private_key.user_key.key_data = private_key;
171 certificate -> nx_secure_x509_private_key.user_key.key_length = priv_len;
172 }
173 else
174 {
175 /* Built-in key type. Attempt to parse the key data. */
176 switch (private_key_type)
177 {
178 case NX_SECURE_X509_KEY_TYPE_RSA_PKCS1_DER:
179 status = _nx_secure_x509_pkcs1_rsa_private_key_parse(private_key, priv_len, &bytes_processed, &certificate -> nx_secure_x509_private_key.rsa_private_key);
180 break;
181 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
182 case NX_SECURE_X509_KEY_TYPE_EC_DER:
183 ec_key = &certificate -> nx_secure_x509_private_key.ec_private_key;
184 status = _nx_secure_x509_ec_private_key_parse(private_key, priv_len, &bytes_processed, ec_key);
185 break;
186 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
187
188 case NX_SECURE_X509_KEY_TYPE_HARDWARE:
189 certificate -> nx_secure_x509_private_key.user_key.key_data = private_key;
190 certificate -> nx_secure_x509_private_key.user_key.key_length = priv_len;
191 status = NX_SUCCESS;
192 break;
193 case NX_SECURE_X509_KEY_TYPE_NONE:
194 default:
195 /* Unknown or invalid key type, return error. */
196 status = NX_SECURE_X509_INVALID_PRIVATE_KEY_TYPE;
197 break;
198 }
199
200 /* See if we had any issues in parsing. */
201 if (status != 0)
202 {
203 return(status);
204 }
205 }
206
207 /* We have a private key, this is a server or client identity certificate. */
208 certificate -> nx_secure_x509_certificate_is_identity_cert = NX_CRYPTO_TRUE;
209 }
210 else
211 {
212 /* No private key? Cannot be an identity certificate. */
213 certificate -> nx_secure_x509_certificate_is_identity_cert = NX_CRYPTO_FALSE;
214 }
215
216 certificate -> nx_secure_x509_next_certificate = NULL;
217
218 return(NX_SECURE_X509_SUCCESS);
219 }
220
221