libcoap 4.3.5-develop-783b531
Loading...
Searching...
No Matches
coap_asn1.c
Go to the documentation of this file.
1/* coap_asn1.c -- ASN.1 handling functions
2 *
3 * Copyright (C) 2020-2026 Jon Shallow <supjps-libcoap@jpshallow.com>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
17
18size_t
19asn1_len(const uint8_t **ptr, size_t *plen) {
20 size_t len = 0;
21
22 if (*plen == 0)
23 return 0;
24 if ((**ptr) & 0x80) {
25 size_t octets = (**ptr) & 0x7f;
26 (*plen)--;
27 (*ptr)++;
28 while (octets) {
29 if (*plen == 0)
30 return 0;
31 len = (len << 8) + (**ptr);
32 (*plen)--;
33 (*ptr)++;
34 octets--;
35 }
36 } else {
37 if (*plen == 0)
38 return 0;
39 len = (**ptr) & 0x7f;
40 (*plen)--;
41 (*ptr)++;
42 }
43 if (len > *plen)
44 return *plen;
45 return len;
46}
47
49asn1_tag_c(const uint8_t **ptr, size_t *plen, int *constructed, int *cls) {
50 coap_asn1_tag_t tag = 0;
51 uint8_t byte;
52
53 if (*plen == 0) {
54 *constructed = 0;
55 *cls = 0;
56 return COAP_ASN1_FAIL;
57 }
58 byte = (**ptr);
59 *constructed = (byte & 0x20) ? 1 : 0;
60 *cls = byte >> 6;
61 tag = byte & 0x1F;
62 (*plen)--;
63 (*ptr)++;
64 if (tag < 0x1F)
65 return tag;
66
67 /* Tag can be one byte or more based on B8 */
68 if (*plen == 0)
69 return COAP_ASN1_FAIL;
70 byte = (**ptr);
71 while (byte & 0x80) {
72 tag = (tag << 7) + (byte & 0x7F);
73 (*plen)--;
74 (*ptr)++;
75 if (*plen == 0 || tag > (INT_MAX >> 7))
76 return COAP_ASN1_FAIL;
77 byte = (**ptr);
78 }
79 /* Do the final one */
80 tag = (tag << 7) + (byte & 0x7F);
81 (*plen)--;
82 (*ptr)++;
83 return tag;
84}
85
86static coap_binary_t *
87get_asn1_tag_internal(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen,
88 asn1_validate validate, uint32_t recursive_check) {
89 int constructed;
90 int class;
91 coap_asn1_tag_t tag = asn1_tag_c(&ptr, &tlen, &constructed, &class);
92 size_t len;
93 coap_binary_t *tag_data;
94
95 if (tag == COAP_ASN1_FAIL)
96 return NULL;
97 len = asn1_len(&ptr, &tlen);
98
99 while (tlen > 0 && len <= tlen) {
100 if (class == 2 && constructed == 1) {
101 /* Skip over element description */
102 tag = asn1_tag_c(&ptr, &tlen, &constructed, &class);
103 if (tag == COAP_ASN1_FAIL)
104 return NULL;
105 len = asn1_len(&ptr, &tlen);
106 }
107 if (tag == ltag) {
108 if (!validate || validate(ptr, len)) {
109 tag_data = coap_new_binary(len);
110 if (tag_data == NULL)
111 return NULL;
112 tag_data->length = len;
113 memcpy(tag_data->s, ptr, len);
114 return tag_data;
115 }
116 }
117 if (tag == 0x10 && constructed == 1) {
118 /* SEQUENCE or SEQUENCE OF */
119 if (recursive_check > 100)
120 return NULL;
121 tag_data = get_asn1_tag_internal(ltag, ptr, len, validate, recursive_check + 1);
122 if (tag_data)
123 return tag_data;
124 }
125 /* Skip over non matching tag */
126 ptr += len;
127 tlen -= len;
128 tag = asn1_tag_c(&ptr, &tlen, &constructed, &class);
129 if (tag == COAP_ASN1_FAIL)
130 return NULL;
131 len = asn1_len(&ptr, &tlen);
132 }
133 return NULL;
134}
135
136/* caller must free off returned coap_binary_t* */
138get_asn1_tag(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen,
139 asn1_validate validate) {
140 return get_asn1_tag_internal(ltag, ptr, tlen, validate, 0);
141}
142
143/* first part of Raw public key, this is the start of the Subject Public Key */
144static const unsigned char cert_asn1_header1[] = {
145 0x30, 0x59, /* SEQUENCE, length 89 bytes */
146 0x30, 0x13, /* SEQUENCE, length 19 bytes */
147 0x06, 0x07, /* OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) */
148 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
149};
150/* PrimeX will get inserted */
151#if 0
1520x06, 0x08, /* OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) */
153 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
154#endif
155static const unsigned char cert_asn1_header2[] = {
156 0x03, 0x42, /* BIT STRING, length 66 bytes */
157 /* Note: 0 bits (0x00) and no compression (0x04) are already in the certificate */
158};
159
161get_asn1_spki(const uint8_t *data, size_t size) {
162 coap_binary_t *pub_key = get_asn1_tag(COAP_ASN1_BITSTRING, data, size, NULL);
164 coap_binary_t *spki = NULL;
165
166 if (pub_key && prime) {
167 size_t header_size = sizeof(cert_asn1_header1) +
168 2 +
169 prime->length +
170 sizeof(cert_asn1_header2);
171 spki = coap_new_binary(header_size + pub_key->length);
172 if (spki) {
173 memcpy(&spki->s[header_size], pub_key->s, pub_key->length);
174 memcpy(spki->s, cert_asn1_header1, sizeof(cert_asn1_header1));
176 spki->s[sizeof(cert_asn1_header1)+1] = (uint8_t)prime->length;
177 memcpy(&spki->s[sizeof(cert_asn1_header1)+2],
178 prime->s, prime->length);
179 memcpy(&spki->s[sizeof(cert_asn1_header1)+2+prime->length],
181 spki->length = header_size + pub_key->length;
182 }
183 }
184 if (pub_key)
185 coap_delete_binary(pub_key);
186 if (prime)
187 coap_delete_binary(prime);
188 return spki;
189}
static const unsigned char cert_asn1_header2[]
Definition coap_asn1.c:155
static coap_binary_t * get_asn1_tag_internal(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen, asn1_validate validate, uint32_t recursive_check)
Definition coap_asn1.c:87
static const unsigned char cert_asn1_header1[]
Definition coap_asn1.c:144
Library specific build wrapper for coap_internal.h.
#define NULL
Definition coap_option.h:30
size_t asn1_len(const uint8_t **ptr, size_t *plen)
Get the asn1 length from the current ptr.
Definition coap_asn1.c:19
coap_binary_t * get_asn1_tag(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen, asn1_validate validate)
Get the asn1 tag and data from the current ptr.
Definition coap_asn1.c:138
coap_asn1_tag_t
coap_binary_t * get_asn1_spki(const uint8_t *data, size_t size)
Abstract SPKI public key from the ASN1.
Definition coap_asn1.c:161
int(* asn1_validate)(const uint8_t *data, size_t size)
Callback to validate the asn1 tag and data.
coap_asn1_tag_t asn1_tag_c(const uint8_t **ptr, size_t *plen, int *constructed, int *cls)
Get the asn1 tag from the current ptr.
Definition coap_asn1.c:49
@ COAP_ASN1_BITSTRING
@ COAP_ASN1_FAIL
@ COAP_ASN1_IDENTIFIER
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition coap_str.c:81
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition coap_str.c:114
CoAP binary data definition.
Definition coap_str.h:57
size_t length
length of binary data
Definition coap_str.h:58
uint8_t * s
binary data
Definition coap_str.h:59