1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * ASN.1 DER parsing 3e5b75505Sopenharmony_ci * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "utils/wpabuf.h" 13e5b75505Sopenharmony_ci#include "asn1.h" 14e5b75505Sopenharmony_ci 15e5b75505Sopenharmony_ciconst struct asn1_oid asn1_sha1_oid = { 16e5b75505Sopenharmony_ci .oid = { 1, 3, 14, 3, 2, 26 }, 17e5b75505Sopenharmony_ci .len = 6 18e5b75505Sopenharmony_ci}; 19e5b75505Sopenharmony_ci 20e5b75505Sopenharmony_ciconst struct asn1_oid asn1_sha256_oid = { 21e5b75505Sopenharmony_ci .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }, 22e5b75505Sopenharmony_ci .len = 9 23e5b75505Sopenharmony_ci}; 24e5b75505Sopenharmony_ci 25e5b75505Sopenharmony_ciconst struct asn1_oid asn1_ec_public_key_oid = { 26e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 10045, 2, 1 }, 27e5b75505Sopenharmony_ci .len = 6 28e5b75505Sopenharmony_ci}; 29e5b75505Sopenharmony_ci 30e5b75505Sopenharmony_ciconst struct asn1_oid asn1_prime256v1_oid = { 31e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 10045, 3, 1, 7 }, 32e5b75505Sopenharmony_ci .len = 7 33e5b75505Sopenharmony_ci}; 34e5b75505Sopenharmony_ci 35e5b75505Sopenharmony_ciconst struct asn1_oid asn1_secp384r1_oid = { 36e5b75505Sopenharmony_ci .oid = { 1, 3, 132, 0, 34 }, 37e5b75505Sopenharmony_ci .len = 5 38e5b75505Sopenharmony_ci}; 39e5b75505Sopenharmony_ci 40e5b75505Sopenharmony_ciconst struct asn1_oid asn1_secp521r1_oid = { 41e5b75505Sopenharmony_ci .oid = { 1, 3, 132, 0, 35 }, 42e5b75505Sopenharmony_ci .len = 5 43e5b75505Sopenharmony_ci}; 44e5b75505Sopenharmony_ci 45e5b75505Sopenharmony_ciconst struct asn1_oid asn1_brainpoolP256r1_oid = { 46e5b75505Sopenharmony_ci .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 }, 47e5b75505Sopenharmony_ci .len = 10 48e5b75505Sopenharmony_ci}; 49e5b75505Sopenharmony_ci 50e5b75505Sopenharmony_ciconst struct asn1_oid asn1_brainpoolP384r1_oid = { 51e5b75505Sopenharmony_ci .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 }, 52e5b75505Sopenharmony_ci .len = 10 53e5b75505Sopenharmony_ci}; 54e5b75505Sopenharmony_ci 55e5b75505Sopenharmony_ciconst struct asn1_oid asn1_brainpoolP512r1_oid = { 56e5b75505Sopenharmony_ci .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 }, 57e5b75505Sopenharmony_ci .len = 10 58e5b75505Sopenharmony_ci}; 59e5b75505Sopenharmony_ci 60e5b75505Sopenharmony_ciconst struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = { 61e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 }, 62e5b75505Sopenharmony_ci .len = 9 63e5b75505Sopenharmony_ci}; 64e5b75505Sopenharmony_ci 65e5b75505Sopenharmony_ciconst struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = { 66e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 }, 67e5b75505Sopenharmony_ci .len = 9 68e5b75505Sopenharmony_ci}; 69e5b75505Sopenharmony_ci 70e5b75505Sopenharmony_ciconst struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = { 71e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 }, 72e5b75505Sopenharmony_ci .len = 9 73e5b75505Sopenharmony_ci}; 74e5b75505Sopenharmony_ci 75e5b75505Sopenharmony_ciconst struct asn1_oid asn1_pbkdf2_oid = { 76e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 113549, 1, 5, 12 }, 77e5b75505Sopenharmony_ci .len = 7 78e5b75505Sopenharmony_ci}; 79e5b75505Sopenharmony_ci 80e5b75505Sopenharmony_ciconst struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = { 81e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 113549, 2, 9 }, 82e5b75505Sopenharmony_ci .len = 6 83e5b75505Sopenharmony_ci}; 84e5b75505Sopenharmony_ci 85e5b75505Sopenharmony_ciconst struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = { 86e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 113549, 2, 10 }, 87e5b75505Sopenharmony_ci .len = 6 88e5b75505Sopenharmony_ci}; 89e5b75505Sopenharmony_ci 90e5b75505Sopenharmony_ciconst struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = { 91e5b75505Sopenharmony_ci .oid = { 1, 2, 840, 113549, 2, 11 }, 92e5b75505Sopenharmony_ci .len = 6 93e5b75505Sopenharmony_ci}; 94e5b75505Sopenharmony_ci 95e5b75505Sopenharmony_ciconst struct asn1_oid asn1_dpp_config_params_oid = { 96e5b75505Sopenharmony_ci .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 }, 97e5b75505Sopenharmony_ci .len = 10 98e5b75505Sopenharmony_ci}; 99e5b75505Sopenharmony_ci 100e5b75505Sopenharmony_ciconst struct asn1_oid asn1_dpp_asymmetric_key_package_oid = { 101e5b75505Sopenharmony_ci .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 }, 102e5b75505Sopenharmony_ci .len = 10 103e5b75505Sopenharmony_ci}; 104e5b75505Sopenharmony_ci 105e5b75505Sopenharmony_ci 106e5b75505Sopenharmony_cistatic int asn1_valid_der_boolean(struct asn1_hdr *hdr) 107e5b75505Sopenharmony_ci{ 108e5b75505Sopenharmony_ci /* Enforce DER requirements for a single way of encoding a BOOLEAN */ 109e5b75505Sopenharmony_ci if (hdr->length != 1) { 110e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)", 111e5b75505Sopenharmony_ci hdr->length); 112e5b75505Sopenharmony_ci return 0; 113e5b75505Sopenharmony_ci } 114e5b75505Sopenharmony_ci 115e5b75505Sopenharmony_ci if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) { 116e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 117e5b75505Sopenharmony_ci "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)", 118e5b75505Sopenharmony_ci hdr->payload[0]); 119e5b75505Sopenharmony_ci return 0; 120e5b75505Sopenharmony_ci } 121e5b75505Sopenharmony_ci 122e5b75505Sopenharmony_ci return 1; 123e5b75505Sopenharmony_ci} 124e5b75505Sopenharmony_ci 125e5b75505Sopenharmony_ci 126e5b75505Sopenharmony_cistatic int asn1_valid_der(struct asn1_hdr *hdr) 127e5b75505Sopenharmony_ci{ 128e5b75505Sopenharmony_ci if (hdr->class != ASN1_CLASS_UNIVERSAL) 129e5b75505Sopenharmony_ci return 1; 130e5b75505Sopenharmony_ci if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr)) 131e5b75505Sopenharmony_ci return 0; 132e5b75505Sopenharmony_ci if (hdr->tag == ASN1_TAG_NULL && hdr->length != 0) 133e5b75505Sopenharmony_ci return 0; 134e5b75505Sopenharmony_ci 135e5b75505Sopenharmony_ci /* Check for allowed primitive/constructed values */ 136e5b75505Sopenharmony_ci if (hdr->constructed && 137e5b75505Sopenharmony_ci (hdr->tag == ASN1_TAG_BOOLEAN || 138e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_INTEGER || 139e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_NULL || 140e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_OID || 141e5b75505Sopenharmony_ci hdr->tag == ANS1_TAG_RELATIVE_OID || 142e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_REAL || 143e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_ENUMERATED || 144e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_BITSTRING || 145e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_OCTETSTRING || 146e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_NUMERICSTRING || 147e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_PRINTABLESTRING || 148e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_T61STRING || 149e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_VIDEOTEXSTRING || 150e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_VISIBLESTRING || 151e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_IA5STRING || 152e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_GRAPHICSTRING || 153e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_GENERALSTRING || 154e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_UNIVERSALSTRING || 155e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_UTF8STRING || 156e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_BMPSTRING || 157e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_CHARACTERSTRING || 158e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_UTCTIME || 159e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_GENERALIZEDTIME || 160e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_TIME)) 161e5b75505Sopenharmony_ci return 0; 162e5b75505Sopenharmony_ci if (!hdr->constructed && 163e5b75505Sopenharmony_ci (hdr->tag == ASN1_TAG_SEQUENCE || 164e5b75505Sopenharmony_ci hdr->tag == ASN1_TAG_SET)) 165e5b75505Sopenharmony_ci return 0; 166e5b75505Sopenharmony_ci 167e5b75505Sopenharmony_ci return 1; 168e5b75505Sopenharmony_ci} 169e5b75505Sopenharmony_ci 170e5b75505Sopenharmony_ci 171e5b75505Sopenharmony_ciint asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) 172e5b75505Sopenharmony_ci{ 173e5b75505Sopenharmony_ci const u8 *pos, *end; 174e5b75505Sopenharmony_ci u8 tmp; 175e5b75505Sopenharmony_ci 176e5b75505Sopenharmony_ci os_memset(hdr, 0, sizeof(*hdr)); 177e5b75505Sopenharmony_ci pos = buf; 178e5b75505Sopenharmony_ci end = buf + len; 179e5b75505Sopenharmony_ci 180e5b75505Sopenharmony_ci if (pos >= end) { 181e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier"); 182e5b75505Sopenharmony_ci return -1; 183e5b75505Sopenharmony_ci } 184e5b75505Sopenharmony_ci hdr->identifier = *pos++; 185e5b75505Sopenharmony_ci hdr->class = hdr->identifier >> 6; 186e5b75505Sopenharmony_ci hdr->constructed = !!(hdr->identifier & (1 << 5)); 187e5b75505Sopenharmony_ci 188e5b75505Sopenharmony_ci if ((hdr->identifier & 0x1f) == 0x1f) { 189e5b75505Sopenharmony_ci size_t ext_len = 0; 190e5b75505Sopenharmony_ci 191e5b75505Sopenharmony_ci hdr->tag = 0; 192e5b75505Sopenharmony_ci if (pos == end || (*pos & 0x7f) == 0) { 193e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 194e5b75505Sopenharmony_ci "ASN.1: Invalid extended tag (first octet has to be included with at least one nonzero bit for the tag value)"); 195e5b75505Sopenharmony_ci return -1; 196e5b75505Sopenharmony_ci } 197e5b75505Sopenharmony_ci do { 198e5b75505Sopenharmony_ci if (pos >= end) { 199e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Identifier " 200e5b75505Sopenharmony_ci "underflow"); 201e5b75505Sopenharmony_ci return -1; 202e5b75505Sopenharmony_ci } 203e5b75505Sopenharmony_ci ext_len++; 204e5b75505Sopenharmony_ci tmp = *pos++; 205e5b75505Sopenharmony_ci wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " 206e5b75505Sopenharmony_ci "0x%02x", tmp); 207e5b75505Sopenharmony_ci hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); 208e5b75505Sopenharmony_ci } while (tmp & 0x80); 209e5b75505Sopenharmony_ci wpa_printf(MSG_MSGDUMP, "ASN.1: Extended Tag: 0x%x (len=%zu)", 210e5b75505Sopenharmony_ci hdr->tag, ext_len); 211e5b75505Sopenharmony_ci if ((hdr->class != ASN1_CLASS_PRIVATE && hdr->tag < 31) || 212e5b75505Sopenharmony_ci ext_len * 7 > sizeof(hdr->tag) * 8) { 213e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 214e5b75505Sopenharmony_ci "ASN.1: Invalid or unsupported (too large) extended Tag: 0x%x (len=%zu)", 215e5b75505Sopenharmony_ci hdr->tag, ext_len); 216e5b75505Sopenharmony_ci return -1; 217e5b75505Sopenharmony_ci } 218e5b75505Sopenharmony_ci } else 219e5b75505Sopenharmony_ci hdr->tag = hdr->identifier & 0x1f; 220e5b75505Sopenharmony_ci 221e5b75505Sopenharmony_ci if (pos >= end) { 222e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: No room for Length"); 223e5b75505Sopenharmony_ci return -1; 224e5b75505Sopenharmony_ci } 225e5b75505Sopenharmony_ci tmp = *pos++; 226e5b75505Sopenharmony_ci if (tmp & 0x80) { 227e5b75505Sopenharmony_ci if (tmp == 0xff) { 228e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " 229e5b75505Sopenharmony_ci "value 0xff used"); 230e5b75505Sopenharmony_ci return -1; 231e5b75505Sopenharmony_ci } 232e5b75505Sopenharmony_ci tmp &= 0x7f; /* number of subsequent octets */ 233e5b75505Sopenharmony_ci hdr->length = 0; 234e5b75505Sopenharmony_ci if (tmp == 0 || pos == end || *pos == 0) { 235e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 236e5b75505Sopenharmony_ci "ASN.1: Definite long form of the length does not start with a nonzero value"); 237e5b75505Sopenharmony_ci return -1; 238e5b75505Sopenharmony_ci } 239e5b75505Sopenharmony_ci if (tmp > 4) { 240e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); 241e5b75505Sopenharmony_ci return -1; 242e5b75505Sopenharmony_ci } 243e5b75505Sopenharmony_ci while (tmp--) { 244e5b75505Sopenharmony_ci if (pos >= end) { 245e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Length " 246e5b75505Sopenharmony_ci "underflow"); 247e5b75505Sopenharmony_ci return -1; 248e5b75505Sopenharmony_ci } 249e5b75505Sopenharmony_ci hdr->length = (hdr->length << 8) | *pos++; 250e5b75505Sopenharmony_ci } 251e5b75505Sopenharmony_ci if (hdr->length < 128) { 252e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 253e5b75505Sopenharmony_ci "ASN.1: Definite long form of the length used with too short length"); 254e5b75505Sopenharmony_ci return -1; 255e5b75505Sopenharmony_ci } 256e5b75505Sopenharmony_ci } else { 257e5b75505Sopenharmony_ci /* Short form - length 0..127 in one octet */ 258e5b75505Sopenharmony_ci hdr->length = tmp; 259e5b75505Sopenharmony_ci } 260e5b75505Sopenharmony_ci 261e5b75505Sopenharmony_ci if (end < pos || hdr->length > (unsigned int) (end - pos)) { 262e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); 263e5b75505Sopenharmony_ci return -1; 264e5b75505Sopenharmony_ci } 265e5b75505Sopenharmony_ci 266e5b75505Sopenharmony_ci hdr->payload = pos; 267e5b75505Sopenharmony_ci 268e5b75505Sopenharmony_ci if (!asn1_valid_der(hdr)) { 269e5b75505Sopenharmony_ci asn1_print_hdr(hdr, "ASN.1: Invalid DER encoding: "); 270e5b75505Sopenharmony_ci return -1; 271e5b75505Sopenharmony_ci } 272e5b75505Sopenharmony_ci return 0; 273e5b75505Sopenharmony_ci} 274e5b75505Sopenharmony_ci 275e5b75505Sopenharmony_ci 276e5b75505Sopenharmony_civoid asn1_print_hdr(const struct asn1_hdr *hdr, const char *title) 277e5b75505Sopenharmony_ci{ 278e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%sclass %d constructed %d tag 0x%x", 279e5b75505Sopenharmony_ci title, hdr->class, hdr->constructed, hdr->tag); 280e5b75505Sopenharmony_ci} 281e5b75505Sopenharmony_ci 282e5b75505Sopenharmony_ci 283e5b75505Sopenharmony_civoid asn1_unexpected(const struct asn1_hdr *hdr, const char *title) 284e5b75505Sopenharmony_ci{ 285e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s - found class %d constructed %d tag 0x%x", 286e5b75505Sopenharmony_ci title, hdr->class, hdr->constructed, hdr->tag); 287e5b75505Sopenharmony_ci} 288e5b75505Sopenharmony_ci 289e5b75505Sopenharmony_ci 290e5b75505Sopenharmony_ciint asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) 291e5b75505Sopenharmony_ci{ 292e5b75505Sopenharmony_ci const u8 *pos, *end; 293e5b75505Sopenharmony_ci unsigned long val; 294e5b75505Sopenharmony_ci u8 tmp; 295e5b75505Sopenharmony_ci 296e5b75505Sopenharmony_ci os_memset(oid, 0, sizeof(*oid)); 297e5b75505Sopenharmony_ci 298e5b75505Sopenharmony_ci pos = buf; 299e5b75505Sopenharmony_ci end = buf + len; 300e5b75505Sopenharmony_ci 301e5b75505Sopenharmony_ci while (pos < end) { 302e5b75505Sopenharmony_ci val = 0; 303e5b75505Sopenharmony_ci 304e5b75505Sopenharmony_ci do { 305e5b75505Sopenharmony_ci if (pos >= end) 306e5b75505Sopenharmony_ci return -1; 307e5b75505Sopenharmony_ci tmp = *pos++; 308e5b75505Sopenharmony_ci val = (val << 7) | (tmp & 0x7f); 309e5b75505Sopenharmony_ci } while (tmp & 0x80); 310e5b75505Sopenharmony_ci 311e5b75505Sopenharmony_ci if (oid->len >= ASN1_MAX_OID_LEN) { 312e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); 313e5b75505Sopenharmony_ci return -1; 314e5b75505Sopenharmony_ci } 315e5b75505Sopenharmony_ci if (oid->len == 0) { 316e5b75505Sopenharmony_ci /* 317e5b75505Sopenharmony_ci * The first octet encodes the first two object 318e5b75505Sopenharmony_ci * identifier components in (X*40) + Y formula. 319e5b75505Sopenharmony_ci * X = 0..2. 320e5b75505Sopenharmony_ci */ 321e5b75505Sopenharmony_ci oid->oid[0] = val / 40; 322e5b75505Sopenharmony_ci if (oid->oid[0] > 2) 323e5b75505Sopenharmony_ci oid->oid[0] = 2; 324e5b75505Sopenharmony_ci oid->oid[1] = val - oid->oid[0] * 40; 325e5b75505Sopenharmony_ci oid->len = 2; 326e5b75505Sopenharmony_ci } else 327e5b75505Sopenharmony_ci oid->oid[oid->len++] = val; 328e5b75505Sopenharmony_ci } 329e5b75505Sopenharmony_ci 330e5b75505Sopenharmony_ci return 0; 331e5b75505Sopenharmony_ci} 332e5b75505Sopenharmony_ci 333e5b75505Sopenharmony_ci 334e5b75505Sopenharmony_ciint asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, 335e5b75505Sopenharmony_ci const u8 **next) 336e5b75505Sopenharmony_ci{ 337e5b75505Sopenharmony_ci struct asn1_hdr hdr; 338e5b75505Sopenharmony_ci 339e5b75505Sopenharmony_ci if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 || 340e5b75505Sopenharmony_ci !asn1_is_oid(&hdr)) { 341e5b75505Sopenharmony_ci asn1_unexpected(&hdr, "ASN.1: Expected OID"); 342e5b75505Sopenharmony_ci return -1; 343e5b75505Sopenharmony_ci } 344e5b75505Sopenharmony_ci 345e5b75505Sopenharmony_ci *next = hdr.payload + hdr.length; 346e5b75505Sopenharmony_ci 347e5b75505Sopenharmony_ci return asn1_parse_oid(hdr.payload, hdr.length, oid); 348e5b75505Sopenharmony_ci} 349e5b75505Sopenharmony_ci 350e5b75505Sopenharmony_ci 351e5b75505Sopenharmony_civoid asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len) 352e5b75505Sopenharmony_ci{ 353e5b75505Sopenharmony_ci char *pos = buf; 354e5b75505Sopenharmony_ci size_t i; 355e5b75505Sopenharmony_ci int ret; 356e5b75505Sopenharmony_ci 357e5b75505Sopenharmony_ci if (len == 0) 358e5b75505Sopenharmony_ci return; 359e5b75505Sopenharmony_ci 360e5b75505Sopenharmony_ci buf[0] = '\0'; 361e5b75505Sopenharmony_ci 362e5b75505Sopenharmony_ci for (i = 0; i < oid->len; i++) { 363e5b75505Sopenharmony_ci ret = os_snprintf(pos, buf + len - pos, 364e5b75505Sopenharmony_ci "%s%lu", 365e5b75505Sopenharmony_ci i == 0 ? "" : ".", oid->oid[i]); 366e5b75505Sopenharmony_ci if (os_snprintf_error(buf + len - pos, ret)) 367e5b75505Sopenharmony_ci break; 368e5b75505Sopenharmony_ci pos += ret; 369e5b75505Sopenharmony_ci } 370e5b75505Sopenharmony_ci buf[len - 1] = '\0'; 371e5b75505Sopenharmony_ci} 372e5b75505Sopenharmony_ci 373e5b75505Sopenharmony_ci 374e5b75505Sopenharmony_cistatic u8 rotate_bits(u8 octet) 375e5b75505Sopenharmony_ci{ 376e5b75505Sopenharmony_ci int i; 377e5b75505Sopenharmony_ci u8 res; 378e5b75505Sopenharmony_ci 379e5b75505Sopenharmony_ci res = 0; 380e5b75505Sopenharmony_ci for (i = 0; i < 8; i++) { 381e5b75505Sopenharmony_ci res <<= 1; 382e5b75505Sopenharmony_ci if (octet & 1) 383e5b75505Sopenharmony_ci res |= 1; 384e5b75505Sopenharmony_ci octet >>= 1; 385e5b75505Sopenharmony_ci } 386e5b75505Sopenharmony_ci 387e5b75505Sopenharmony_ci return res; 388e5b75505Sopenharmony_ci} 389e5b75505Sopenharmony_ci 390e5b75505Sopenharmony_ci 391e5b75505Sopenharmony_ciunsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) 392e5b75505Sopenharmony_ci{ 393e5b75505Sopenharmony_ci unsigned long val = 0; 394e5b75505Sopenharmony_ci const u8 *pos = buf; 395e5b75505Sopenharmony_ci 396e5b75505Sopenharmony_ci /* BER requires that unused bits are zero, so we can ignore the number 397e5b75505Sopenharmony_ci * of unused bits */ 398e5b75505Sopenharmony_ci pos++; 399e5b75505Sopenharmony_ci 400e5b75505Sopenharmony_ci if (len >= 2) 401e5b75505Sopenharmony_ci val |= rotate_bits(*pos++); 402e5b75505Sopenharmony_ci if (len >= 3) 403e5b75505Sopenharmony_ci val |= ((unsigned long) rotate_bits(*pos++)) << 8; 404e5b75505Sopenharmony_ci if (len >= 4) 405e5b75505Sopenharmony_ci val |= ((unsigned long) rotate_bits(*pos++)) << 16; 406e5b75505Sopenharmony_ci if (len >= 5) 407e5b75505Sopenharmony_ci val |= ((unsigned long) rotate_bits(*pos++)) << 24; 408e5b75505Sopenharmony_ci if (len >= 6) 409e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " 410e5b75505Sopenharmony_ci "(BIT STRING length %lu)", 411e5b75505Sopenharmony_ci __func__, (unsigned long) len); 412e5b75505Sopenharmony_ci 413e5b75505Sopenharmony_ci return val; 414e5b75505Sopenharmony_ci} 415e5b75505Sopenharmony_ci 416e5b75505Sopenharmony_ci 417e5b75505Sopenharmony_ciint asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b) 418e5b75505Sopenharmony_ci{ 419e5b75505Sopenharmony_ci size_t i; 420e5b75505Sopenharmony_ci 421e5b75505Sopenharmony_ci if (a->len != b->len) 422e5b75505Sopenharmony_ci return 0; 423e5b75505Sopenharmony_ci 424e5b75505Sopenharmony_ci for (i = 0; i < a->len; i++) { 425e5b75505Sopenharmony_ci if (a->oid[i] != b->oid[i]) 426e5b75505Sopenharmony_ci return 0; 427e5b75505Sopenharmony_ci } 428e5b75505Sopenharmony_ci 429e5b75505Sopenharmony_ci return 1; 430e5b75505Sopenharmony_ci} 431e5b75505Sopenharmony_ci 432e5b75505Sopenharmony_ci 433e5b75505Sopenharmony_ciint asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next) 434e5b75505Sopenharmony_ci{ 435e5b75505Sopenharmony_ci struct asn1_hdr hdr; 436e5b75505Sopenharmony_ci size_t left; 437e5b75505Sopenharmony_ci const u8 *pos; 438e5b75505Sopenharmony_ci int value; 439e5b75505Sopenharmony_ci 440e5b75505Sopenharmony_ci if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 || 441e5b75505Sopenharmony_ci !asn1_is_integer(&hdr)) { 442e5b75505Sopenharmony_ci asn1_unexpected(&hdr, "ASN.1: Expected INTEGER"); 443e5b75505Sopenharmony_ci return -1; 444e5b75505Sopenharmony_ci } 445e5b75505Sopenharmony_ci 446e5b75505Sopenharmony_ci *next = hdr.payload + hdr.length; 447e5b75505Sopenharmony_ci pos = hdr.payload; 448e5b75505Sopenharmony_ci left = hdr.length; 449e5b75505Sopenharmony_ci if (left > sizeof(value)) { 450e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)", 451e5b75505Sopenharmony_ci hdr.length); 452e5b75505Sopenharmony_ci return -1; 453e5b75505Sopenharmony_ci } 454e5b75505Sopenharmony_ci value = 0; 455e5b75505Sopenharmony_ci while (left) { 456e5b75505Sopenharmony_ci value <<= 8; 457e5b75505Sopenharmony_ci value |= *pos++; 458e5b75505Sopenharmony_ci left--; 459e5b75505Sopenharmony_ci } 460e5b75505Sopenharmony_ci 461e5b75505Sopenharmony_ci *integer = value; 462e5b75505Sopenharmony_ci return 0; 463e5b75505Sopenharmony_ci} 464e5b75505Sopenharmony_ci 465e5b75505Sopenharmony_ci 466e5b75505Sopenharmony_ciint asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr, 467e5b75505Sopenharmony_ci const u8 **next) 468e5b75505Sopenharmony_ci{ 469e5b75505Sopenharmony_ci if (asn1_get_next(buf, len, hdr) < 0 || !asn1_is_sequence(hdr)) { 470e5b75505Sopenharmony_ci asn1_unexpected(hdr, "ASN.1: Expected SEQUENCE"); 471e5b75505Sopenharmony_ci return -1; 472e5b75505Sopenharmony_ci } 473e5b75505Sopenharmony_ci 474e5b75505Sopenharmony_ci if (next) 475e5b75505Sopenharmony_ci *next = hdr->payload + hdr->length; 476e5b75505Sopenharmony_ci return 0; 477e5b75505Sopenharmony_ci} 478e5b75505Sopenharmony_ci 479e5b75505Sopenharmony_ci 480e5b75505Sopenharmony_ciint asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid, 481e5b75505Sopenharmony_ci const u8 **params, size_t *params_len, const u8 **next) 482e5b75505Sopenharmony_ci{ 483e5b75505Sopenharmony_ci const u8 *pos = buf, *end = buf + len; 484e5b75505Sopenharmony_ci struct asn1_hdr hdr; 485e5b75505Sopenharmony_ci 486e5b75505Sopenharmony_ci /* 487e5b75505Sopenharmony_ci * AlgorithmIdentifier ::= SEQUENCE { 488e5b75505Sopenharmony_ci * algorithm OBJECT IDENTIFIER, 489e5b75505Sopenharmony_ci * parameters ANY DEFINED BY algorithm OPTIONAL} 490e5b75505Sopenharmony_ci */ 491e5b75505Sopenharmony_ci if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 || 492e5b75505Sopenharmony_ci asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0) 493e5b75505Sopenharmony_ci return -1; 494e5b75505Sopenharmony_ci 495e5b75505Sopenharmony_ci if (params && params_len) { 496e5b75505Sopenharmony_ci *params = pos; 497e5b75505Sopenharmony_ci *params_len = hdr.payload + hdr.length - pos; 498e5b75505Sopenharmony_ci } 499e5b75505Sopenharmony_ci 500e5b75505Sopenharmony_ci return 0; 501e5b75505Sopenharmony_ci} 502e5b75505Sopenharmony_ci 503e5b75505Sopenharmony_ci 504e5b75505Sopenharmony_civoid asn1_put_integer(struct wpabuf *buf, int val) 505e5b75505Sopenharmony_ci{ 506e5b75505Sopenharmony_ci u8 bin[4]; 507e5b75505Sopenharmony_ci int zeros; 508e5b75505Sopenharmony_ci 509e5b75505Sopenharmony_ci WPA_PUT_BE32(bin, val); 510e5b75505Sopenharmony_ci zeros = 0; 511e5b75505Sopenharmony_ci while (zeros < 3 && bin[zeros] == 0) 512e5b75505Sopenharmony_ci zeros++; 513e5b75505Sopenharmony_ci wpabuf_put_u8(buf, ASN1_TAG_INTEGER); 514e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 4 - zeros); 515e5b75505Sopenharmony_ci wpabuf_put_data(buf, &bin[zeros], 4 - zeros); 516e5b75505Sopenharmony_ci} 517e5b75505Sopenharmony_ci 518e5b75505Sopenharmony_ci 519e5b75505Sopenharmony_cistatic void asn1_put_len(struct wpabuf *buf, size_t len) 520e5b75505Sopenharmony_ci{ 521e5b75505Sopenharmony_ci if (len <= 0x7f) { 522e5b75505Sopenharmony_ci wpabuf_put_u8(buf, len); 523e5b75505Sopenharmony_ci } else if (len <= 0xff) { 524e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 0x80 | 1); 525e5b75505Sopenharmony_ci wpabuf_put_u8(buf, len); 526e5b75505Sopenharmony_ci } else if (len <= 0xffff) { 527e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 0x80 | 2); 528e5b75505Sopenharmony_ci wpabuf_put_be16(buf, len); 529e5b75505Sopenharmony_ci } else if (len <= 0xffffff) { 530e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 0x80 | 3); 531e5b75505Sopenharmony_ci wpabuf_put_be24(buf, len); 532e5b75505Sopenharmony_ci } else { 533e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 0x80 | 4); 534e5b75505Sopenharmony_ci wpabuf_put_be32(buf, len); 535e5b75505Sopenharmony_ci } 536e5b75505Sopenharmony_ci} 537e5b75505Sopenharmony_ci 538e5b75505Sopenharmony_ci 539e5b75505Sopenharmony_civoid asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val) 540e5b75505Sopenharmony_ci{ 541e5b75505Sopenharmony_ci wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING); 542e5b75505Sopenharmony_ci asn1_put_len(buf, wpabuf_len(val)); 543e5b75505Sopenharmony_ci wpabuf_put_buf(buf, val); 544e5b75505Sopenharmony_ci} 545e5b75505Sopenharmony_ci 546e5b75505Sopenharmony_ci 547e5b75505Sopenharmony_civoid asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid) 548e5b75505Sopenharmony_ci{ 549e5b75505Sopenharmony_ci u8 *len; 550e5b75505Sopenharmony_ci size_t i; 551e5b75505Sopenharmony_ci 552e5b75505Sopenharmony_ci if (oid->len < 2) 553e5b75505Sopenharmony_ci return; 554e5b75505Sopenharmony_ci wpabuf_put_u8(buf, ASN1_TAG_OID); 555e5b75505Sopenharmony_ci len = wpabuf_put(buf, 1); 556e5b75505Sopenharmony_ci wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]); 557e5b75505Sopenharmony_ci for (i = 2; i < oid->len; i++) { 558e5b75505Sopenharmony_ci unsigned long val = oid->oid[i]; 559e5b75505Sopenharmony_ci u8 bytes[8]; 560e5b75505Sopenharmony_ci int idx = 0; 561e5b75505Sopenharmony_ci 562e5b75505Sopenharmony_ci while (val) { 563e5b75505Sopenharmony_ci bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f); 564e5b75505Sopenharmony_ci idx++; 565e5b75505Sopenharmony_ci val >>= 7; 566e5b75505Sopenharmony_ci } 567e5b75505Sopenharmony_ci if (idx == 0) { 568e5b75505Sopenharmony_ci bytes[idx] = 0; 569e5b75505Sopenharmony_ci idx = 1; 570e5b75505Sopenharmony_ci } 571e5b75505Sopenharmony_ci while (idx > 0) { 572e5b75505Sopenharmony_ci idx--; 573e5b75505Sopenharmony_ci wpabuf_put_u8(buf, bytes[idx]); 574e5b75505Sopenharmony_ci } 575e5b75505Sopenharmony_ci } 576e5b75505Sopenharmony_ci *len = (u8 *) wpabuf_put(buf, 0) - len - 1; 577e5b75505Sopenharmony_ci} 578e5b75505Sopenharmony_ci 579e5b75505Sopenharmony_ci 580e5b75505Sopenharmony_civoid asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag, 581e5b75505Sopenharmony_ci size_t len) 582e5b75505Sopenharmony_ci{ 583e5b75505Sopenharmony_ci wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag); 584e5b75505Sopenharmony_ci asn1_put_len(buf, len); 585e5b75505Sopenharmony_ci} 586e5b75505Sopenharmony_ci 587e5b75505Sopenharmony_ci 588e5b75505Sopenharmony_civoid asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload) 589e5b75505Sopenharmony_ci{ 590e5b75505Sopenharmony_ci asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE, 591e5b75505Sopenharmony_ci wpabuf_len(payload)); 592e5b75505Sopenharmony_ci wpabuf_put_buf(buf, payload); 593e5b75505Sopenharmony_ci} 594e5b75505Sopenharmony_ci 595e5b75505Sopenharmony_ci 596e5b75505Sopenharmony_civoid asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload) 597e5b75505Sopenharmony_ci{ 598e5b75505Sopenharmony_ci asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET, 599e5b75505Sopenharmony_ci wpabuf_len(payload)); 600e5b75505Sopenharmony_ci wpabuf_put_buf(buf, payload); 601e5b75505Sopenharmony_ci} 602e5b75505Sopenharmony_ci 603e5b75505Sopenharmony_ci 604e5b75505Sopenharmony_civoid asn1_put_utf8string(struct wpabuf *buf, const char *val) 605e5b75505Sopenharmony_ci{ 606e5b75505Sopenharmony_ci asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING, 607e5b75505Sopenharmony_ci os_strlen(val)); 608e5b75505Sopenharmony_ci wpabuf_put_str(buf, val); 609e5b75505Sopenharmony_ci} 610e5b75505Sopenharmony_ci 611e5b75505Sopenharmony_ci 612e5b75505Sopenharmony_cistruct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid, 613e5b75505Sopenharmony_ci const struct wpabuf *params) 614e5b75505Sopenharmony_ci{ 615e5b75505Sopenharmony_ci struct wpabuf *buf; 616e5b75505Sopenharmony_ci size_t len; 617e5b75505Sopenharmony_ci 618e5b75505Sopenharmony_ci /* 619e5b75505Sopenharmony_ci * AlgorithmIdentifier ::= SEQUENCE { 620e5b75505Sopenharmony_ci * algorithm OBJECT IDENTIFIER, 621e5b75505Sopenharmony_ci * parameters ANY DEFINED BY algorithm OPTIONAL} 622e5b75505Sopenharmony_ci */ 623e5b75505Sopenharmony_ci 624e5b75505Sopenharmony_ci len = 100; 625e5b75505Sopenharmony_ci if (params) 626e5b75505Sopenharmony_ci len += wpabuf_len(params); 627e5b75505Sopenharmony_ci buf = wpabuf_alloc(len); 628e5b75505Sopenharmony_ci if (!buf) 629e5b75505Sopenharmony_ci return NULL; 630e5b75505Sopenharmony_ci asn1_put_oid(buf, oid); 631e5b75505Sopenharmony_ci if (params) 632e5b75505Sopenharmony_ci wpabuf_put_buf(buf, params); 633e5b75505Sopenharmony_ci return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); 634e5b75505Sopenharmony_ci} 635e5b75505Sopenharmony_ci 636e5b75505Sopenharmony_ci 637e5b75505Sopenharmony_cistruct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag) 638e5b75505Sopenharmony_ci{ 639e5b75505Sopenharmony_ci struct wpabuf *res; 640e5b75505Sopenharmony_ci 641e5b75505Sopenharmony_ci if (!buf) 642e5b75505Sopenharmony_ci return NULL; 643e5b75505Sopenharmony_ci res = wpabuf_alloc(10 + wpabuf_len(buf)); 644e5b75505Sopenharmony_ci if (res) { 645e5b75505Sopenharmony_ci asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf)); 646e5b75505Sopenharmony_ci wpabuf_put_buf(res, buf); 647e5b75505Sopenharmony_ci } 648e5b75505Sopenharmony_ci wpabuf_clear_free(buf); 649e5b75505Sopenharmony_ci return res; 650e5b75505Sopenharmony_ci} 651