/* Get a component of Distinguished Name (e.i. subject or issuer) USING the oid tag. * dn can be either cert->subject or cert->issuer. * dn_len would be cert->subject_len or cert->issuer_len. * * Common types: * CN: struct sc_object_id type = {{2, 5, 4, 3, -1}}; * Country: struct sc_object_id type = {{2, 5, 4, 6, -1}}; * L: struct sc_object_id type = {{2, 5, 4, 7, -1}}; * S: struct sc_object_id type = {{2, 5, 4, 8, -1}}; * O: struct sc_object_id type = {{2, 5, 4, 10, -1}}; * OU: struct sc_object_id type = {{2, 5, 4, 11, -1}}; * * if *name is NULL, sc_pkcs15_get_name_from_dn will allocate space for name. */ int sc_pkcs15_get_name_from_dn(struct sc_context *ctx, const u8 *dn, size_t dn_len, const struct sc_object_id *type, u8 **name, size_t *name_len) { const u8 *rdn = NULL; const u8 *next_ava = NULL; size_t rdn_len = 0; size_t next_ava_len = 0; int rv; rdn = sc_asn1_skip_tag(ctx, &dn, &dn_len, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &rdn_len); if (rdn == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of Distiguished Name"); for (next_ava = rdn, next_ava_len = rdn_len; next_ava_len; ) { const u8 *ava, *dummy, *oidp; struct sc_object_id oid; size_t ava_len, dummy_len, oid_len; /* unwrap the set and point to the next ava */ ava = sc_asn1_skip_tag(ctx, &next_ava, &next_ava_len, SC_ASN1_TAG_SET | SC_ASN1_CONS, &ava_len); if (ava == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA"); /* It would be nice to use sc_asn1_decode here to parse the entire AVA, but we are missing 1 critical * function in the templates: the ability to accept any tag for value. This prevents us from just * grabbing the value as is out of the template. AVA's can have tags of PRINTABLE_STRING, * TELETEXSTRING, T61STRING or UTF8_STRING with PRINTABLE_STRING and UTF8_STRING being the most common. * The other feature that would be nice is returning a pointer to our requested data using the space * of the parent (basically what this code is doing here), rather than allocating and copying. */ /* unwrap the sequence */ dummy = ava; dummy_len = ava_len; ava = sc_asn1_skip_tag(ctx, &dummy, &dummy_len, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &ava_len); if (ava == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA"); /* unwrap the oid */ oidp = sc_asn1_skip_tag(ctx, &ava, &ava_len, SC_ASN1_TAG_OBJECT, &oid_len); if (ava == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA OID"); /* Convert to OID */ rv = sc_asn1_decode_object_id(oidp, oid_len, &oid); if (rv != SC_SUCCESS) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA OID"); if (sc_compare_oid(&oid, type) == 0) continue; /* Yes, then return the name */ dummy = sc_asn1_skip_tag(ctx, &ava, &ava_len, ava[0] & SC_ASN1_TAG_PRIMITIVE, &dummy_len); if (*name == NULL) { *name = malloc(dummy_len); if (*name == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); *name_len = dummy_len; } *name_len = MIN(dummy_len, *name_len); memcpy(*name, dummy, *name_len); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } LOG_FUNC_RETURN(ctx, SC_ERROR_ASN1_OBJECT_NOT_FOUND); }
/* Get a specific extension from the cert. * The extension is identified by it's oid value. * NOTE: extensions can occur in any number or any order, which is why we * can't parse them with a single pass of the asn1 decoder. * If is_critical is supplied, then it is set to 1 if the extention is critical * and 0 if it is not. * The data in the extension is extension specific. * The following are common extension values: * Subject Key ID: struct sc_object_id type = {{2, 5, 29, 14, -1}}; * Key Usage: struct sc_object_id type = {{2, 5, 29, 15, -1}}; * Subject Alt Name: struct sc_object_id type = {{2, 5, 29, 17, -1}}; * Basic Constraints: struct sc_object_id type = {{2, 5, 29, 19, -1}}; * CRL Distribution Points: struct sc_object_id type = {{2, 5, 29, 31, -1}}; * Certificate Policies: struct sc_object_id type = {{2, 5, 29, 32, -1}}; * Extended Key Usage: struct sc_object_id type = {{2, 5, 29, 37, -1}}; * * if *ext_val is NULL, sc_pkcs15_get_extension will allocate space for ext_val. */ int sc_pkcs15_get_extension(struct sc_context *ctx, struct sc_pkcs15_cert *cert, const struct sc_object_id *type, u8 **ext_val, size_t *ext_val_len, int *is_critical) { const u8 *ext = NULL; const u8 *next_ext = NULL; size_t ext_len = 0; size_t next_ext_len = 0; struct sc_object_id oid; u8 *val = NULL; size_t val_len = 0; int critical; int r; struct sc_asn1_entry asn1_cert_ext[] = { { "x509v3 entry OID", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, &oid, 0 }, { "criticalFlag", SC_ASN1_BOOLEAN, SC_ASN1_TAG_BOOLEAN, SC_ASN1_OPTIONAL, &critical, NULL }, { "extensionValue",SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, &val, &val_len }, { NULL, 0, 0, 0, NULL, NULL } }; for (next_ext = cert->extensions, next_ext_len = cert->extensions_len; next_ext_len; ) { /* unwrap the set and point to the next ava */ ext = sc_asn1_skip_tag(ctx, &next_ext, &next_ext_len, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, &ext_len); if (ext == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "ASN.1 decoding of AVA"); /* * use the sc_asn1_decoder for clarity. NOTE it would be more efficient to do this by hand * so we avoid the man malloc/frees here, but one hopes that one day the asn1_decode will allow * a 'static pointer' flag that returns a const pointer to the actual asn1 space so we only need * to make a final copy of the extension value before we return */ critical = 0; r = sc_asn1_decode(ctx, asn1_cert_ext, ext, ext_len, NULL, NULL); if (r < 0) LOG_FUNC_RETURN(ctx, r); /* is it the RN we are looking for */ if (sc_compare_oid(&oid, type) != 0) { if (*ext_val == NULL) { *ext_val = val; val = NULL; *ext_val_len = val_len; /* do not free here -- return the allocated value to caller */ } else { *ext_val_len = MIN(*ext_val_len, val_len); memcpy(*ext_val, val, *ext_val_len); free(val); } if (is_critical) *is_critical = critical; r = val_len; LOG_FUNC_RETURN(ctx, r); } if (val) { free(val); val = NULL; } } if (val) free(val); LOG_FUNC_RETURN(ctx, SC_ERROR_ASN1_OBJECT_NOT_FOUND); }
const u8 *sc_asn1_verify_tag(sc_context_t *ctx, const u8 * buf, size_t buflen, unsigned int tag_in, size_t *taglen_out) { return sc_asn1_skip_tag(ctx, &buf, &buflen, tag_in, taglen_out); }