libcoap 4.3.5-develop-fe41b51
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)
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
86/* caller must free off returned coap_binary_t* */
88get_asn1_tag(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen,
89 asn1_validate validate) {
90 int constructed;
91 int class;
92 coap_asn1_tag_t tag = asn1_tag_c(&ptr, &tlen, &constructed, &class);
93 size_t len;
94 coap_binary_t *tag_data;
95
96 if (tag == COAP_ASN1_FAIL)
97 return NULL;
98 len = asn1_len(&ptr, &tlen);
99
100 while (tlen > 0 && len <= tlen) {
101 if (class == 2 && constructed == 1) {
102 /* Skip over element description */
103 tag = asn1_tag_c(&ptr, &tlen, &constructed, &class);
104 if (tag == COAP_ASN1_FAIL)
105 return NULL;
106 len = asn1_len(&ptr, &tlen);
107 }
108 if (tag == ltag) {
109 if (!validate || validate(ptr, len)) {
110 tag_data = coap_new_binary(len);
111 if (tag_data == NULL)
112 return NULL;
113 tag_data->length = len;
114 memcpy(tag_data->s, ptr, len);
115 return tag_data;
116 }
117 }
118 if (tag == 0x10 && constructed == 1) {
119 /* SEQUENCE or SEQUENCE OF */
120 tag_data = get_asn1_tag(ltag, ptr, len, validate);
121 if (tag_data)
122 return tag_data;
123 }
124 /* Skip over non matching tag */
125 ptr += len;
126 tlen -= len;
127 tag = asn1_tag_c(&ptr, &tlen, &constructed, &class);
128 if (tag == COAP_ASN1_FAIL)
129 return NULL;
130 len = asn1_len(&ptr, &tlen);
131 }
132 return NULL;
133}
134
135/* first part of Raw public key, this is the start of the Subject Public Key */
136static const unsigned char cert_asn1_header1[] = {
137 0x30, 0x59, /* SEQUENCE, length 89 bytes */
138 0x30, 0x13, /* SEQUENCE, length 19 bytes */
139 0x06, 0x07, /* OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) */
140 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
141};
142/* PrimeX will get inserted */
143#if 0
1440x06, 0x08, /* OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) */
145 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
146#endif
147static const unsigned char cert_asn1_header2[] = {
148 0x03, 0x42, /* BIT STRING, length 66 bytes */
149 /* Note: 0 bits (0x00) and no compression (0x04) are already in the certificate */
150};
151
153get_asn1_spki(const uint8_t *data, size_t size) {
154 coap_binary_t *pub_key = get_asn1_tag(COAP_ASN1_BITSTRING, data, size, NULL);
156 coap_binary_t *spki = NULL;
157
158 if (pub_key && prime) {
159 size_t header_size = sizeof(cert_asn1_header1) +
160 2 +
161 prime->length +
162 sizeof(cert_asn1_header2);
163 spki = coap_new_binary(header_size + pub_key->length);
164 if (spki) {
165 memcpy(&spki->s[header_size], pub_key->s, pub_key->length);
166 memcpy(spki->s, cert_asn1_header1, sizeof(cert_asn1_header1));
168 spki->s[sizeof(cert_asn1_header1)+1] = (uint8_t)prime->length;
169 memcpy(&spki->s[sizeof(cert_asn1_header1)+2],
170 prime->s, prime->length);
171 memcpy(&spki->s[sizeof(cert_asn1_header1)+2+prime->length],
173 spki->length = header_size + pub_key->length;
174 }
175 }
176 if (pub_key)
177 coap_delete_binary(pub_key);
178 if (prime)
179 coap_delete_binary(prime);
180 return spki;
181}
static const unsigned char cert_asn1_header2[]
Definition coap_asn1.c:147
static const unsigned char cert_asn1_header1[]
Definition coap_asn1.c:136
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:88
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:153
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