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 - PKCS#7 parsing                        */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SECURE_SOURCE_CODE
23 
24 
25 #include "nx_secure_x509.h"
26 
27 /**************************************************************************/
28 /*                                                                        */
29 /*  FUNCTION                                               RELEASE        */
30 /*                                                                        */
31 /*    _nx_secure_x509_pkcs7_decode                        PORTABLE C      */
32 /*                                                           6.1.6        */
33 /*  AUTHOR                                                                */
34 /*                                                                        */
35 /*    Timothy Stapko, Microsoft Corporation                               */
36 /*                                                                        */
37 /*  DESCRIPTION                                                           */
38 /*                                                                        */
39 /*    This function decodes a PKCS#7 (RFC 5652) certificate signature     */
40 /*    and returns a pointer to the encapsulated hash for signature        */
41 /*    verification by the caller. Also returned is the OID for the        */
42 /*    signature algorithm.                                                */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    signature_pointer                     Pointer to PCKS#7 signature   */
47 /*    signature_length                      Length of entire signagure    */
48 /*    signature_oid                         Pointer to signature OID      */
49 /*    signature_oid_length                  Return length of OID          */
50 /*    hash_data                             Pointer to hash data          */
51 /*    hash_length                           Return length of hash         */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    status                                Signature validity status     */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _nx_secure_x509_asn1_tlv_block_parse  Parse ASN.1 block             */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    _nx_secure_x509_certificate_verify    Verify a certificate          */
64 /*    _nx_secure_x509_crl_verify            Verify revocation list        */
65 /*    _nx_secure_tls_process_server_key_exchange                          */
66 /*                                          Process ServerKeyExchange     */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Timothy Stapko           Initial Version 6.0           */
73 /*  09-30-2020     Timothy Stapko           Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*  04-02-2021     Timothy Stapko           Modified comment(s),          */
76 /*                                            removed dependency on TLS,  */
77 /*                                            resulting in version 6.1.6  */
78 /*                                                                        */
79 /**************************************************************************/
_nx_secure_x509_pkcs7_decode(const UCHAR * signature_pointer,UINT signature_length,const UCHAR ** signature_oid,UINT * signature_oid_length,const UCHAR ** hash_data,UINT * hash_length)80 UINT _nx_secure_x509_pkcs7_decode(const UCHAR *signature_pointer, UINT signature_length,
81                                   const UCHAR **signature_oid, UINT *signature_oid_length,
82                                   const UCHAR **hash_data, UINT *hash_length)
83 {
84 UINT         i;
85 USHORT       tlv_type;
86 USHORT       tlv_type_class;
87 ULONG        tlv_length;
88 const UCHAR *tlv_data = NX_CRYPTO_NULL;
89 ULONG        header_length;
90 ULONG        seq_length;
91 UINT         status;
92 const UCHAR *signature_data = NX_CRYPTO_NULL;
93 ULONG        remaining_length;
94 
95     /* Certificate signatures encrypted with RSA use PKCS#7 encoding (RFC 5652) which
96      * has the following format:
97      *    1 byte header (0x00)
98      *    Padding type byte (should be < 2)
99      *    <Padding>
100      *    1 byte padding terminator (always 0x00)
101      *    ASN.1 encoded signature
102      *       Signature Sequence
103      *           OID sequence
104      *              signature algorithm OID(s) (can be multiple)
105      *              NULL ASN.1 object terminator
106      *           Octet string of hash value
107      *    1 byte end padding (0x01)
108      */
109 
110     signature_data = signature_pointer;
111     remaining_length = signature_length;
112 
113     /* Check padding type. */
114     if (signature_data[1] >= 2)
115     {
116         /* Invalid PKCS#7 encoding or decryption failure. */
117         return(NX_SECURE_X509_PKCS7_PARSING_FAILED);
118     }
119 
120     /* Loop through padding - skip the first 2 bytes of padding type.
121      * Also ensure that we don't run past the end of the buffer if
122      * the NULL terminator isn't found. */
123     i = 2;
124     while (i < signature_length)
125     {
126         if (signature_data[i] == 0x00)
127         {
128             break;
129         }
130         i++;
131     }
132 
133     /* Skip over the padding null-terminator. */
134     i++;
135 
136     /* Make sure we actually saw a NULL byte. */
137     if (i >= signature_length)
138     {
139         return(NX_SECURE_X509_PKCS7_PARSING_FAILED);
140     }
141 
142     /* Advance our working pointer. */
143     signature_data = &signature_data[i];
144     remaining_length -= i;
145 
146     /* Now we have our ASN.1-encoded signature. */
147     status = _nx_secure_x509_asn1_tlv_block_parse(signature_data, &remaining_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
148 
149     /*  Make sure we parsed a proper ASN.1 sequence. */
150     if (status != 0 || tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
151     {
152         return(NX_SECURE_X509_PKCS7_PARSING_FAILED);
153     }
154 
155     /* Advance our working pointer and adjust remaining length. */
156     signature_data = tlv_data;
157     remaining_length = tlv_length;
158 
159     /* Next up is the OID sequence. */
160     status = _nx_secure_x509_asn1_tlv_block_parse(signature_data, &remaining_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
161 
162     /*  Make sure we parsed a proper ASN.1 sequence. */
163     if (status != 0 || tlv_type != NX_SECURE_ASN_TAG_SEQUENCE || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
164     {
165         return(NX_SECURE_X509_PKCS7_PARSING_FAILED);
166     }
167     signature_data = tlv_data;
168     seq_length = tlv_length;
169 
170     /* Next we parse the OID(s). */
171     do
172     {
173         /* Parse at least 1 OID. */
174         status = _nx_secure_x509_asn1_tlv_block_parse(signature_data, &seq_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
175 
176         /*  Make sure we parsed a proper ASN.1 sequence. */
177         if (status != 0 || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
178         {
179             return(NX_SECURE_X509_PKCS7_PARSING_FAILED);
180         }
181 
182         /* Adjust our buffer pointer. */
183         signature_data = &signature_data[tlv_length + header_length];
184 
185         /* If we see a NULL tag, we are at the end of the list. */
186         if (tlv_type == NX_SECURE_ASN_TAG_NULL)
187         {
188             break;
189         }
190 
191         /* Save off the OID. */
192         *signature_oid = tlv_data;
193         *signature_oid_length = tlv_length;
194     } while (tlv_type == NX_SECURE_ASN_TAG_OID);
195 
196     /* Finally, we should be at the signature hash itself. */
197     status = _nx_secure_x509_asn1_tlv_block_parse(signature_data, &remaining_length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
198 
199     /*  Make sure we parsed a proper ASN.1 sequence. */
200     if (status != 0 || tlv_type != NX_SECURE_ASN_TAG_OCTET_STRING || tlv_type_class != NX_SECURE_ASN_TAG_CLASS_UNIVERSAL)
201     {
202         return(NX_SECURE_X509_PKCS7_PARSING_FAILED);
203     }
204 
205     /* Return pointer to hash data and its length. */
206     *hash_data = tlv_data;
207     *hash_length = tlv_length;
208 
209     /* Signature is valid. */
210     return(NX_SECURE_X509_SUCCESS);
211 }
212 
213