1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * X.509 Certificate Signing Request (CSR) parsing 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 57901324dSJerome Forissier * SPDX-License-Identifier: Apache-2.0 6817466cbSJens Wiklander * 7817466cbSJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 8817466cbSJens Wiklander * not use this file except in compliance with the License. 9817466cbSJens Wiklander * You may obtain a copy of the License at 10817466cbSJens Wiklander * 11817466cbSJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 12817466cbSJens Wiklander * 13817466cbSJens Wiklander * Unless required by applicable law or agreed to in writing, software 14817466cbSJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15817466cbSJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16817466cbSJens Wiklander * See the License for the specific language governing permissions and 17817466cbSJens Wiklander * limitations under the License. 18817466cbSJens Wiklander */ 19817466cbSJens Wiklander /* 20817466cbSJens Wiklander * The ITU-T X.509 standard defines a certificate format for PKI. 21817466cbSJens Wiklander * 22817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) 23817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) 24817466cbSJens Wiklander * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) 25817466cbSJens Wiklander * 26817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf 27817466cbSJens Wiklander * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf 28817466cbSJens Wiklander */ 29817466cbSJens Wiklander 307901324dSJerome Forissier #include "common.h" 31817466cbSJens Wiklander 32817466cbSJens Wiklander #if defined(MBEDTLS_X509_CSR_PARSE_C) 33817466cbSJens Wiklander 34817466cbSJens Wiklander #include "mbedtls/x509_csr.h" 3511fa71b9SJerome Forissier #include "mbedtls/error.h" 36817466cbSJens Wiklander #include "mbedtls/oid.h" 373d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 38817466cbSJens Wiklander 39817466cbSJens Wiklander #include <string.h> 40817466cbSJens Wiklander 41817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 42817466cbSJens Wiklander #include "mbedtls/pem.h" 43817466cbSJens Wiklander #endif 44817466cbSJens Wiklander 45817466cbSJens Wiklander #include "mbedtls/platform.h" 46817466cbSJens Wiklander 47817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) 48817466cbSJens Wiklander #include <stdio.h> 49817466cbSJens Wiklander #endif 50817466cbSJens Wiklander 51817466cbSJens Wiklander /* 52817466cbSJens Wiklander * Version ::= INTEGER { v1(0) } 53817466cbSJens Wiklander */ 54817466cbSJens Wiklander static int x509_csr_get_version(unsigned char **p, 55817466cbSJens Wiklander const unsigned char *end, 56817466cbSJens Wiklander int *ver) 57817466cbSJens Wiklander { 5811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 59817466cbSJens Wiklander 60*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_int(p, end, ver)) != 0) { 61*32b31808SJens Wiklander if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { 62817466cbSJens Wiklander *ver = 0; 63*32b31808SJens Wiklander return 0; 64817466cbSJens Wiklander } 65817466cbSJens Wiklander 66*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, ret); 67817466cbSJens Wiklander } 68817466cbSJens Wiklander 69*32b31808SJens Wiklander return 0; 70*32b31808SJens Wiklander } 71*32b31808SJens Wiklander 72*32b31808SJens Wiklander /* 73*32b31808SJens Wiklander * Parse CSR extension requests in DER format 74*32b31808SJens Wiklander */ 75*32b31808SJens Wiklander static int x509_csr_parse_extensions(mbedtls_x509_csr *csr, 76*32b31808SJens Wiklander unsigned char **p, const unsigned char *end) 77*32b31808SJens Wiklander { 78*32b31808SJens Wiklander int ret; 79*32b31808SJens Wiklander size_t len; 80*32b31808SJens Wiklander unsigned char *end_ext_data; 81*32b31808SJens Wiklander while (*p < end) { 82*32b31808SJens Wiklander mbedtls_x509_buf extn_oid = { 0, 0, NULL }; 83*32b31808SJens Wiklander int ext_type = 0; 84*32b31808SJens Wiklander 85*32b31808SJens Wiklander /* Read sequence tag */ 86*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 87*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 88*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 89*32b31808SJens Wiklander } 90*32b31808SJens Wiklander 91*32b31808SJens Wiklander end_ext_data = *p + len; 92*32b31808SJens Wiklander 93*32b31808SJens Wiklander /* Get extension ID */ 94*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &extn_oid.len, 95*32b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) { 96*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 97*32b31808SJens Wiklander } 98*32b31808SJens Wiklander 99*32b31808SJens Wiklander extn_oid.tag = MBEDTLS_ASN1_OID; 100*32b31808SJens Wiklander extn_oid.p = *p; 101*32b31808SJens Wiklander *p += extn_oid.len; 102*32b31808SJens Wiklander 103*32b31808SJens Wiklander /* Data should be octet string type */ 104*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len, 105*32b31808SJens Wiklander MBEDTLS_ASN1_OCTET_STRING)) != 0) { 106*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 107*32b31808SJens Wiklander } 108*32b31808SJens Wiklander 109*32b31808SJens Wiklander if (*p + len != end_ext_data) { 110*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 111*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 112*32b31808SJens Wiklander } 113*32b31808SJens Wiklander 114*32b31808SJens Wiklander /* 115*32b31808SJens Wiklander * Detect supported extensions and skip unsupported extensions 116*32b31808SJens Wiklander */ 117*32b31808SJens Wiklander ret = mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type); 118*32b31808SJens Wiklander 119*32b31808SJens Wiklander if (ret == 0) { 120*32b31808SJens Wiklander /* Forbid repeated extensions */ 121*32b31808SJens Wiklander if ((csr->ext_types & ext_type) != 0) { 122*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 123*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_INVALID_DATA); 124*32b31808SJens Wiklander } 125*32b31808SJens Wiklander 126*32b31808SJens Wiklander csr->ext_types |= ext_type; 127*32b31808SJens Wiklander 128*32b31808SJens Wiklander switch (ext_type) { 129*32b31808SJens Wiklander case MBEDTLS_X509_EXT_KEY_USAGE: 130*32b31808SJens Wiklander /* Parse key usage */ 131*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_key_usage(p, end_ext_data, 132*32b31808SJens Wiklander &csr->key_usage)) != 0) { 133*32b31808SJens Wiklander return ret; 134*32b31808SJens Wiklander } 135*32b31808SJens Wiklander break; 136*32b31808SJens Wiklander 137*32b31808SJens Wiklander case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: 138*32b31808SJens Wiklander /* Parse subject alt name */ 139*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_data, 140*32b31808SJens Wiklander &csr->subject_alt_names)) != 0) { 141*32b31808SJens Wiklander return ret; 142*32b31808SJens Wiklander } 143*32b31808SJens Wiklander break; 144*32b31808SJens Wiklander 145*32b31808SJens Wiklander case MBEDTLS_X509_EXT_NS_CERT_TYPE: 146*32b31808SJens Wiklander /* Parse netscape certificate type */ 147*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_ns_cert_type(p, end_ext_data, 148*32b31808SJens Wiklander &csr->ns_cert_type)) != 0) { 149*32b31808SJens Wiklander return ret; 150*32b31808SJens Wiklander } 151*32b31808SJens Wiklander break; 152*32b31808SJens Wiklander default: 153*32b31808SJens Wiklander break; 154*32b31808SJens Wiklander } 155*32b31808SJens Wiklander } 156*32b31808SJens Wiklander *p = end_ext_data; 157*32b31808SJens Wiklander } 158*32b31808SJens Wiklander 159*32b31808SJens Wiklander if (*p != end) { 160*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 161*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 162*32b31808SJens Wiklander } 163*32b31808SJens Wiklander 164*32b31808SJens Wiklander return 0; 165*32b31808SJens Wiklander } 166*32b31808SJens Wiklander 167*32b31808SJens Wiklander /* 168*32b31808SJens Wiklander * Parse CSR attributes in DER format 169*32b31808SJens Wiklander */ 170*32b31808SJens Wiklander static int x509_csr_parse_attributes(mbedtls_x509_csr *csr, 171*32b31808SJens Wiklander const unsigned char *start, const unsigned char *end) 172*32b31808SJens Wiklander { 173*32b31808SJens Wiklander int ret; 174*32b31808SJens Wiklander size_t len; 175*32b31808SJens Wiklander unsigned char *end_attr_data; 176*32b31808SJens Wiklander unsigned char **p = (unsigned char **) &start; 177*32b31808SJens Wiklander 178*32b31808SJens Wiklander while (*p < end) { 179*32b31808SJens Wiklander mbedtls_x509_buf attr_oid = { 0, 0, NULL }; 180*32b31808SJens Wiklander 181*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 182*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 183*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 184*32b31808SJens Wiklander } 185*32b31808SJens Wiklander end_attr_data = *p + len; 186*32b31808SJens Wiklander 187*32b31808SJens Wiklander /* Get attribute ID */ 188*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end_attr_data, &attr_oid.len, 189*32b31808SJens Wiklander MBEDTLS_ASN1_OID)) != 0) { 190*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 191*32b31808SJens Wiklander } 192*32b31808SJens Wiklander 193*32b31808SJens Wiklander attr_oid.tag = MBEDTLS_ASN1_OID; 194*32b31808SJens Wiklander attr_oid.p = *p; 195*32b31808SJens Wiklander *p += attr_oid.len; 196*32b31808SJens Wiklander 197*32b31808SJens Wiklander /* Check that this is an extension-request attribute */ 198*32b31808SJens Wiklander if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS9_CSR_EXT_REQ, &attr_oid) == 0) { 199*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 200*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)) != 0) { 201*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 202*32b31808SJens Wiklander } 203*32b31808SJens Wiklander 204*32b31808SJens Wiklander if ((ret = mbedtls_asn1_get_tag(p, end, &len, 205*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 206*32b31808SJens Wiklander 0) { 207*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); 208*32b31808SJens Wiklander } 209*32b31808SJens Wiklander 210*32b31808SJens Wiklander if ((ret = x509_csr_parse_extensions(csr, p, *p + len)) != 0) { 211*32b31808SJens Wiklander return ret; 212*32b31808SJens Wiklander } 213*32b31808SJens Wiklander 214*32b31808SJens Wiklander if (*p != end_attr_data) { 215*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 216*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 217*32b31808SJens Wiklander } 218*32b31808SJens Wiklander } 219*32b31808SJens Wiklander 220*32b31808SJens Wiklander *p = end_attr_data; 221*32b31808SJens Wiklander } 222*32b31808SJens Wiklander 223*32b31808SJens Wiklander if (*p != end) { 224*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 225*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 226*32b31808SJens Wiklander } 227*32b31808SJens Wiklander 228*32b31808SJens Wiklander return 0; 229817466cbSJens Wiklander } 230817466cbSJens Wiklander 231817466cbSJens Wiklander /* 232817466cbSJens Wiklander * Parse a CSR in DER format 233817466cbSJens Wiklander */ 234817466cbSJens Wiklander int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr, 235817466cbSJens Wiklander const unsigned char *buf, size_t buflen) 236817466cbSJens Wiklander { 23711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 238817466cbSJens Wiklander size_t len; 239817466cbSJens Wiklander unsigned char *p, *end; 240817466cbSJens Wiklander mbedtls_x509_buf sig_params; 241817466cbSJens Wiklander 242817466cbSJens Wiklander memset(&sig_params, 0, sizeof(mbedtls_x509_buf)); 243817466cbSJens Wiklander 244817466cbSJens Wiklander /* 245817466cbSJens Wiklander * Check for valid input 246817466cbSJens Wiklander */ 247*32b31808SJens Wiklander if (csr == NULL || buf == NULL || buflen == 0) { 248*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 249*32b31808SJens Wiklander } 250817466cbSJens Wiklander 251817466cbSJens Wiklander mbedtls_x509_csr_init(csr); 252817466cbSJens Wiklander 253817466cbSJens Wiklander /* 254817466cbSJens Wiklander * first copy the raw DER data 255817466cbSJens Wiklander */ 256817466cbSJens Wiklander p = mbedtls_calloc(1, len = buflen); 257817466cbSJens Wiklander 258*32b31808SJens Wiklander if (p == NULL) { 259*32b31808SJens Wiklander return MBEDTLS_ERR_X509_ALLOC_FAILED; 260*32b31808SJens Wiklander } 261817466cbSJens Wiklander 262817466cbSJens Wiklander memcpy(p, buf, buflen); 263817466cbSJens Wiklander 264817466cbSJens Wiklander csr->raw.p = p; 265817466cbSJens Wiklander csr->raw.len = len; 266817466cbSJens Wiklander end = p + len; 267817466cbSJens Wiklander 268817466cbSJens Wiklander /* 269817466cbSJens Wiklander * CertificationRequest ::= SEQUENCE { 270817466cbSJens Wiklander * certificationRequestInfo CertificationRequestInfo, 271817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 272817466cbSJens Wiklander * signature BIT STRING 273817466cbSJens Wiklander * } 274817466cbSJens Wiklander */ 275817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 276*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 277817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 278*32b31808SJens Wiklander return MBEDTLS_ERR_X509_INVALID_FORMAT; 279817466cbSJens Wiklander } 280817466cbSJens Wiklander 281*32b31808SJens Wiklander if (len != (size_t) (end - p)) { 282817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 283*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, 284*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 285817466cbSJens Wiklander } 286817466cbSJens Wiklander 287817466cbSJens Wiklander /* 288817466cbSJens Wiklander * CertificationRequestInfo ::= SEQUENCE { 289817466cbSJens Wiklander */ 290817466cbSJens Wiklander csr->cri.p = p; 291817466cbSJens Wiklander 292817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 293*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 294817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 295*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 296817466cbSJens Wiklander } 297817466cbSJens Wiklander 298817466cbSJens Wiklander end = p + len; 299817466cbSJens Wiklander csr->cri.len = end - csr->cri.p; 300817466cbSJens Wiklander 301817466cbSJens Wiklander /* 302817466cbSJens Wiklander * Version ::= INTEGER { v1(0) } 303817466cbSJens Wiklander */ 304*32b31808SJens Wiklander if ((ret = x509_csr_get_version(&p, end, &csr->version)) != 0) { 305817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 306*32b31808SJens Wiklander return ret; 307817466cbSJens Wiklander } 308817466cbSJens Wiklander 309*32b31808SJens Wiklander if (csr->version != 0) { 310817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 311*32b31808SJens Wiklander return MBEDTLS_ERR_X509_UNKNOWN_VERSION; 312817466cbSJens Wiklander } 313817466cbSJens Wiklander 314817466cbSJens Wiklander csr->version++; 315817466cbSJens Wiklander 316817466cbSJens Wiklander /* 317817466cbSJens Wiklander * subject Name 318817466cbSJens Wiklander */ 319817466cbSJens Wiklander csr->subject_raw.p = p; 320817466cbSJens Wiklander 321817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 322*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { 323817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 324*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 325817466cbSJens Wiklander } 326817466cbSJens Wiklander 327*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_name(&p, p + len, &csr->subject)) != 0) { 328817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 329*32b31808SJens Wiklander return ret; 330817466cbSJens Wiklander } 331817466cbSJens Wiklander 332817466cbSJens Wiklander csr->subject_raw.len = p - csr->subject_raw.p; 333817466cbSJens Wiklander 334817466cbSJens Wiklander /* 335817466cbSJens Wiklander * subjectPKInfo SubjectPublicKeyInfo 336817466cbSJens Wiklander */ 337*32b31808SJens Wiklander if ((ret = mbedtls_pk_parse_subpubkey(&p, end, &csr->pk)) != 0) { 338817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 339*32b31808SJens Wiklander return ret; 340817466cbSJens Wiklander } 341817466cbSJens Wiklander 342817466cbSJens Wiklander /* 343817466cbSJens Wiklander * attributes [0] Attributes 344817466cbSJens Wiklander * 345817466cbSJens Wiklander * The list of possible attributes is open-ended, though RFC 2985 346817466cbSJens Wiklander * (PKCS#9) defines a few in section 5.4. We currently don't support any, 347817466cbSJens Wiklander * so we just ignore them. This is a safe thing to do as the worst thing 348817466cbSJens Wiklander * that could happen is that we issue a certificate that does not match 349817466cbSJens Wiklander * the requester's expectations - this cannot cause a violation of our 350817466cbSJens Wiklander * signature policies. 351817466cbSJens Wiklander */ 352817466cbSJens Wiklander if ((ret = mbedtls_asn1_get_tag(&p, end, &len, 353*32b31808SJens Wiklander MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC)) != 354*32b31808SJens Wiklander 0) { 355817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 356*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); 357*32b31808SJens Wiklander } 358*32b31808SJens Wiklander 359*32b31808SJens Wiklander if ((ret = x509_csr_parse_attributes(csr, p, p + len)) != 0) { 360*32b31808SJens Wiklander mbedtls_x509_csr_free(csr); 361*32b31808SJens Wiklander return ret; 362817466cbSJens Wiklander } 363817466cbSJens Wiklander 364817466cbSJens Wiklander p += len; 365817466cbSJens Wiklander 366817466cbSJens Wiklander end = csr->raw.p + csr->raw.len; 367817466cbSJens Wiklander 368817466cbSJens Wiklander /* 369817466cbSJens Wiklander * signatureAlgorithm AlgorithmIdentifier, 370817466cbSJens Wiklander * signature BIT STRING 371817466cbSJens Wiklander */ 372*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_alg(&p, end, &csr->sig_oid, &sig_params)) != 0) { 373817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 374*32b31808SJens Wiklander return ret; 375817466cbSJens Wiklander } 376817466cbSJens Wiklander 377817466cbSJens Wiklander if ((ret = mbedtls_x509_get_sig_alg(&csr->sig_oid, &sig_params, 378817466cbSJens Wiklander &csr->sig_md, &csr->sig_pk, 379*32b31808SJens Wiklander &csr->sig_opts)) != 0) { 380817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 381*32b31808SJens Wiklander return MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG; 382817466cbSJens Wiklander } 383817466cbSJens Wiklander 384*32b31808SJens Wiklander if ((ret = mbedtls_x509_get_sig(&p, end, &csr->sig)) != 0) { 385817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 386*32b31808SJens Wiklander return ret; 387817466cbSJens Wiklander } 388817466cbSJens Wiklander 389*32b31808SJens Wiklander if (p != end) { 390817466cbSJens Wiklander mbedtls_x509_csr_free(csr); 391*32b31808SJens Wiklander return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, 392*32b31808SJens Wiklander MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); 393817466cbSJens Wiklander } 394817466cbSJens Wiklander 395*32b31808SJens Wiklander return 0; 396817466cbSJens Wiklander } 397817466cbSJens Wiklander 398817466cbSJens Wiklander /* 399817466cbSJens Wiklander * Parse a CSR, allowing for PEM or raw DER encoding 400817466cbSJens Wiklander */ 401817466cbSJens Wiklander int mbedtls_x509_csr_parse(mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen) 402817466cbSJens Wiklander { 403817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 40411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 405817466cbSJens Wiklander size_t use_len; 406817466cbSJens Wiklander mbedtls_pem_context pem; 407817466cbSJens Wiklander #endif 408817466cbSJens Wiklander 409817466cbSJens Wiklander /* 410817466cbSJens Wiklander * Check for valid input 411817466cbSJens Wiklander */ 412*32b31808SJens Wiklander if (csr == NULL || buf == NULL || buflen == 0) { 413*32b31808SJens Wiklander return MBEDTLS_ERR_X509_BAD_INPUT_DATA; 414*32b31808SJens Wiklander } 415817466cbSJens Wiklander 416817466cbSJens Wiklander #if defined(MBEDTLS_PEM_PARSE_C) 417817466cbSJens Wiklander /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ 418*32b31808SJens Wiklander if (buf[buflen - 1] == '\0') { 4193d3b0591SJens Wiklander mbedtls_pem_init(&pem); 420817466cbSJens Wiklander ret = mbedtls_pem_read_buffer(&pem, 421817466cbSJens Wiklander "-----BEGIN CERTIFICATE REQUEST-----", 422817466cbSJens Wiklander "-----END CERTIFICATE REQUEST-----", 423817466cbSJens Wiklander buf, NULL, 0, &use_len); 424*32b31808SJens Wiklander if (ret == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { 4255b25c76aSJerome Forissier ret = mbedtls_pem_read_buffer(&pem, 4265b25c76aSJerome Forissier "-----BEGIN NEW CERTIFICATE REQUEST-----", 4275b25c76aSJerome Forissier "-----END NEW CERTIFICATE REQUEST-----", 4285b25c76aSJerome Forissier buf, NULL, 0, &use_len); 4295b25c76aSJerome Forissier } 430817466cbSJens Wiklander 431*32b31808SJens Wiklander if (ret == 0) { 432817466cbSJens Wiklander /* 433817466cbSJens Wiklander * Was PEM encoded, parse the result 434817466cbSJens Wiklander */ 4353d3b0591SJens Wiklander ret = mbedtls_x509_csr_parse_der(csr, pem.buf, pem.buflen); 4365b25c76aSJerome Forissier } 437817466cbSJens Wiklander 438817466cbSJens Wiklander mbedtls_pem_free(&pem); 439*32b31808SJens Wiklander if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { 440*32b31808SJens Wiklander return ret; 441*32b31808SJens Wiklander } 442817466cbSJens Wiklander } 443817466cbSJens Wiklander #endif /* MBEDTLS_PEM_PARSE_C */ 444*32b31808SJens Wiklander return mbedtls_x509_csr_parse_der(csr, buf, buflen); 445817466cbSJens Wiklander } 446817466cbSJens Wiklander 447817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO) 448817466cbSJens Wiklander /* 449817466cbSJens Wiklander * Load a CSR into the structure 450817466cbSJens Wiklander */ 451817466cbSJens Wiklander int mbedtls_x509_csr_parse_file(mbedtls_x509_csr *csr, const char *path) 452817466cbSJens Wiklander { 45311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 454817466cbSJens Wiklander size_t n; 455817466cbSJens Wiklander unsigned char *buf; 456817466cbSJens Wiklander 457*32b31808SJens Wiklander if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) { 458*32b31808SJens Wiklander return ret; 459*32b31808SJens Wiklander } 460817466cbSJens Wiklander 461817466cbSJens Wiklander ret = mbedtls_x509_csr_parse(csr, buf, n); 462817466cbSJens Wiklander 4633d3b0591SJens Wiklander mbedtls_platform_zeroize(buf, n); 464817466cbSJens Wiklander mbedtls_free(buf); 465817466cbSJens Wiklander 466*32b31808SJens Wiklander return ret; 467817466cbSJens Wiklander } 468817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */ 469817466cbSJens Wiklander 470*32b31808SJens Wiklander #if !defined(MBEDTLS_X509_REMOVE_INFO) 471817466cbSJens Wiklander #define BEFORE_COLON 14 472817466cbSJens Wiklander #define BC "14" 473817466cbSJens Wiklander /* 474817466cbSJens Wiklander * Return an informational string about the CSR. 475817466cbSJens Wiklander */ 476817466cbSJens Wiklander int mbedtls_x509_csr_info(char *buf, size_t size, const char *prefix, 477817466cbSJens Wiklander const mbedtls_x509_csr *csr) 478817466cbSJens Wiklander { 47911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 480817466cbSJens Wiklander size_t n; 481817466cbSJens Wiklander char *p; 482817466cbSJens Wiklander char key_size_str[BEFORE_COLON]; 483817466cbSJens Wiklander 484817466cbSJens Wiklander p = buf; 485817466cbSJens Wiklander n = size; 486817466cbSJens Wiklander 487817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "%sCSR version : %d", 488817466cbSJens Wiklander prefix, csr->version); 489817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 490817466cbSJens Wiklander 491817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject name : ", prefix); 492817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 493817466cbSJens Wiklander ret = mbedtls_x509_dn_gets(p, n, &csr->subject); 494817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 495817466cbSJens Wiklander 496817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssigned using : ", prefix); 497817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 498817466cbSJens Wiklander 499817466cbSJens Wiklander ret = mbedtls_x509_sig_alg_gets(p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md, 500817466cbSJens Wiklander csr->sig_opts); 501817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 502817466cbSJens Wiklander 503817466cbSJens Wiklander if ((ret = mbedtls_x509_key_size_helper(key_size_str, BEFORE_COLON, 504*32b31808SJens Wiklander mbedtls_pk_get_name(&csr->pk))) != 0) { 505*32b31808SJens Wiklander return ret; 506817466cbSJens Wiklander } 507817466cbSJens Wiklander 508817466cbSJens Wiklander ret = mbedtls_snprintf(p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str, 509817466cbSJens Wiklander (int) mbedtls_pk_get_bitlen(&csr->pk)); 510817466cbSJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 511817466cbSJens Wiklander 512*32b31808SJens Wiklander /* 513*32b31808SJens Wiklander * Optional extensions 514*32b31808SJens Wiklander */ 515*32b31808SJens Wiklander 516*32b31808SJens Wiklander if (csr->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME) { 517*32b31808SJens Wiklander ret = mbedtls_snprintf(p, n, "\n%ssubject alt name :", prefix); 518*32b31808SJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 519*32b31808SJens Wiklander 520*32b31808SJens Wiklander if ((ret = mbedtls_x509_info_subject_alt_name(&p, &n, 521*32b31808SJens Wiklander &csr->subject_alt_names, 522*32b31808SJens Wiklander prefix)) != 0) { 523*32b31808SJens Wiklander return ret; 524817466cbSJens Wiklander } 525*32b31808SJens Wiklander } 526*32b31808SJens Wiklander 527*32b31808SJens Wiklander if (csr->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) { 528*32b31808SJens Wiklander ret = mbedtls_snprintf(p, n, "\n%scert. type : ", prefix); 529*32b31808SJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 530*32b31808SJens Wiklander 531*32b31808SJens Wiklander if ((ret = mbedtls_x509_info_cert_type(&p, &n, csr->ns_cert_type)) != 0) { 532*32b31808SJens Wiklander return ret; 533*32b31808SJens Wiklander } 534*32b31808SJens Wiklander } 535*32b31808SJens Wiklander 536*32b31808SJens Wiklander if (csr->ext_types & MBEDTLS_X509_EXT_KEY_USAGE) { 537*32b31808SJens Wiklander ret = mbedtls_snprintf(p, n, "\n%skey usage : ", prefix); 538*32b31808SJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 539*32b31808SJens Wiklander 540*32b31808SJens Wiklander if ((ret = mbedtls_x509_info_key_usage(&p, &n, csr->key_usage)) != 0) { 541*32b31808SJens Wiklander return ret; 542*32b31808SJens Wiklander } 543*32b31808SJens Wiklander } 544*32b31808SJens Wiklander 545*32b31808SJens Wiklander if (csr->ext_types != 0) { 546*32b31808SJens Wiklander ret = mbedtls_snprintf(p, n, "\n"); 547*32b31808SJens Wiklander MBEDTLS_X509_SAFE_SNPRINTF; 548*32b31808SJens Wiklander } 549*32b31808SJens Wiklander 550*32b31808SJens Wiklander return (int) (size - n); 551*32b31808SJens Wiklander } 552*32b31808SJens Wiklander #endif /* MBEDTLS_X509_REMOVE_INFO */ 553817466cbSJens Wiklander 554817466cbSJens Wiklander /* 555817466cbSJens Wiklander * Initialize a CSR 556817466cbSJens Wiklander */ 557817466cbSJens Wiklander void mbedtls_x509_csr_init(mbedtls_x509_csr *csr) 558817466cbSJens Wiklander { 559817466cbSJens Wiklander memset(csr, 0, sizeof(mbedtls_x509_csr)); 560817466cbSJens Wiklander } 561817466cbSJens Wiklander 562817466cbSJens Wiklander /* 563817466cbSJens Wiklander * Unallocate all CSR data 564817466cbSJens Wiklander */ 565817466cbSJens Wiklander void mbedtls_x509_csr_free(mbedtls_x509_csr *csr) 566817466cbSJens Wiklander { 567*32b31808SJens Wiklander if (csr == NULL) { 568817466cbSJens Wiklander return; 569*32b31808SJens Wiklander } 570817466cbSJens Wiklander 571817466cbSJens Wiklander mbedtls_pk_free(&csr->pk); 572817466cbSJens Wiklander 573817466cbSJens Wiklander #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) 574817466cbSJens Wiklander mbedtls_free(csr->sig_opts); 575817466cbSJens Wiklander #endif 576817466cbSJens Wiklander 577*32b31808SJens Wiklander mbedtls_asn1_free_named_data_list_shallow(csr->subject.next); 578*32b31808SJens Wiklander mbedtls_asn1_sequence_free(csr->subject_alt_names.next); 579817466cbSJens Wiklander 580*32b31808SJens Wiklander if (csr->raw.p != NULL) { 5813d3b0591SJens Wiklander mbedtls_platform_zeroize(csr->raw.p, csr->raw.len); 582817466cbSJens Wiklander mbedtls_free(csr->raw.p); 583817466cbSJens Wiklander } 584817466cbSJens Wiklander 5853d3b0591SJens Wiklander mbedtls_platform_zeroize(csr, sizeof(mbedtls_x509_csr)); 586817466cbSJens Wiklander } 587817466cbSJens Wiklander 588817466cbSJens Wiklander #endif /* MBEDTLS_X509_CSR_PARSE_C */ 589