1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 #include "tomcrypt_private.h"
11 
12 /**
13   @file x509_decode_public_key_from_certificate.c
14   ASN.1 DER/X.509, decode a certificate
15 */
16 
17 #ifdef LTC_DER
18 
19 /* Check if it looks like a SubjectPublicKeyInfo */
20 #define LOOKS_LIKE_SPKI(l) ((l) != NULL)              \
21 && ((l)->type == LTC_ASN1_SEQUENCE)                   \
22 && ((l)->child != NULL)                               \
23 && ((l)->child->type == LTC_ASN1_OBJECT_IDENTIFIER)   \
24 && ((l)->next != NULL)                                \
25 && ((l)->next->type == LTC_ASN1_BIT_STRING)
26 
27 /**
28   Try to decode the public key from a X.509 certificate
29    @param in               The input buffer
30    @param inlen            The length of the input buffer
31    @param algorithm        One out of the enum #public_key_algorithms
32    @param param_type       The parameters' type out of the enum ltc_asn1_type
33    @param parameters       The parameters to include
34    @param parameters_len   [in/out] The number of parameters to include
35    @param callback         The callback
36    @param ctx              The context passed to the callback
37    @return CRYPT_OK on success, CRYPT_NOP if no SubjectPublicKeyInfo was found
38 */
x509_decode_public_key_from_certificate(const unsigned char * in,unsigned long inlen,enum ltc_oid_id algorithm,ltc_asn1_type param_type,ltc_asn1_list * parameters,unsigned long * parameters_len,public_key_decode_cb callback,void * ctx)39 int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen,
40                                             enum ltc_oid_id algorithm, ltc_asn1_type param_type,
41                                             ltc_asn1_list* parameters, unsigned long *parameters_len,
42                                             public_key_decode_cb callback, void *ctx)
43 {
44    int err;
45    unsigned char *tmpbuf;
46    unsigned long tmpbuf_len, tmp_inlen;
47    ltc_asn1_list *decoded_list = NULL, *l;
48 
49    LTC_ARGCHK(in    != NULL);
50    LTC_ARGCHK(inlen != 0);
51 
52    tmpbuf_len = inlen;
53    tmpbuf = XCALLOC(1, tmpbuf_len);
54    if (tmpbuf == NULL) {
55        err = CRYPT_MEM;
56        goto LBL_OUT;
57    }
58 
59    tmp_inlen = inlen;
60    if ((err = der_decode_sequence_flexi(in, &tmp_inlen, &decoded_list)) == CRYPT_OK) {
61       l = decoded_list;
62 
63       err = CRYPT_NOP;
64 
65       /* Move 2 levels up in the tree
66          SEQUENCE
67              SEQUENCE
68                  ...
69        */
70       if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
71          l = l->child;
72          if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
73             l = l->child;
74 
75             /* Move forward in the tree until we find this combination
76                  ...
77                  SEQUENCE
78                      SEQUENCE
79                          OBJECT IDENTIFIER <some PKA OID, e.g. 1.2.840.113549.1.1.1>
80                          NULL
81                      BIT STRING
82              */
83             do {
84                /* The additional check for l->data is there to make sure
85                 * we won't try to decode a list that has been 'shrunk'
86                 */
87                if ((l->type == LTC_ASN1_SEQUENCE)
88                      && (l->data != NULL)
89                      && LOOKS_LIKE_SPKI(l->child)) {
90                   if (algorithm == PKA_EC) {
91                      err = ecc_import_subject_public_key_info(l->data, l->size, ctx);
92                   } else {
93                      err = x509_decode_subject_public_key_info(l->data, l->size,
94                                                                algorithm, tmpbuf, &tmpbuf_len,
95                                                                param_type, parameters, parameters_len);
96                      if (err == CRYPT_OK) {
97                         err = callback(tmpbuf, tmpbuf_len, ctx);
98                         goto LBL_OUT;
99                      }
100                   }
101                }
102                l = l->next;
103             } while(l);
104          }
105       }
106    }
107 
108 LBL_OUT:
109    if (decoded_list) der_free_sequence_flexi(decoded_list);
110    if (tmpbuf != NULL) XFREE(tmpbuf);
111 
112    return err;
113 }
114 
115 #endif
116 
117 /* ref:         $Format:%D$ */
118 /* git commit:  $Format:%H$ */
119 /* commit time: $Format:%ai$ */
120