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