/** * Parse X.501 attributes */ bool parse_attributes(chunk_t blob, scep_attributes_t *attrs) { asn1_parser_t *parser; chunk_t object; int oid = OID_UNKNOWN; int objectID; bool success = FALSE; parser = asn1_parser_create(attributesObjects, blob); DBG(DBG_CONTROL | DBG_PARSING, DBG_log("parsing attributes") ) while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case ATTRIBUTE_OBJ_TYPE: oid = asn1_known_oid(object); break; case ATTRIBUTE_OBJ_VALUE: if (!extract_attribute(oid, object, parser->get_level(parser), attrs)) { goto end; } } } success = parser->success(parser); end: parser->destroy(parser); return success; }
/** * Load a RSA public key from an ASN.1 encoded blob. */ static public_key_t *parse_rsa_public_key(chunk_t blob) { chunk_t n, e; asn1_parser_t *parser; chunk_t object; int objectID; bool success = FALSE; parser = asn1_parser_create(pubkeyObjects, blob); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case PUB_KEY_MODULUS: n = object; break; case PUB_KEY_EXPONENT: e = object; break; } } success = parser->success(parser); parser->destroy(parser); if (!success) { return NULL; } return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END); }
/** * Parse PKCS#7 ContentInfo object */ bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo) { asn1_parser_t *parser; chunk_t object; int objectID; bool success = FALSE; parser = asn1_parser_create(contentInfoObjects, blob); parser->set_top_level(parser, level0); while (parser->iterate(parser, &objectID, &object)) { if (objectID == PKCS7_INFO_TYPE) { cInfo->type = asn1_known_oid(object); if (cInfo->type < OID_PKCS7_DATA || cInfo->type > OID_PKCS7_ENCRYPTED_DATA) { DBG1(DBG_LIB, "unknown pkcs7 content type"); goto end; } } else if (objectID == PKCS7_INFO_CONTENT) { cInfo->content = object; } } success = parser->success(parser); end: parser->destroy(parser); return success; }
/** * Load a generic private key from an ASN.1 encoded blob */ static private_key_t *parse_private_key(chunk_t blob) { asn1_parser_t *parser; chunk_t object, params = chunk_empty; int objectID; private_key_t *key = NULL; key_type_t type = KEY_ANY; parser = asn1_parser_create(pkinfoObjects, blob); parser->set_flags(parser, FALSE, TRUE); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case PKINFO_PRIVATE_KEY_ALGORITHM: { int oid = asn1_parse_algorithmIdentifier(object, parser->get_level(parser) + 1, ¶ms); switch (oid) { case OID_RSA_ENCRYPTION: type = KEY_RSA; break; case OID_EC_PUBLICKEY: type = KEY_ECDSA; break; default: /* key type not supported */ goto end; } break; } case PKINFO_PRIVATE_KEY: { DBG2(DBG_ASN, "-- > --"); if (params.ptr) { key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, BUILD_BLOB_ALGID_PARAMS, params, BUILD_BLOB_ASN1_DER, object, BUILD_END); } else { key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, BUILD_BLOB_ASN1_DER, object, BUILD_END); } DBG2(DBG_ASN, "-- < --"); break; } } } end: parser->destroy(parser); return key; }
/** * Load a generic public key from an ASN.1 encoded blob */ static public_key_t *parse_public_key(chunk_t blob) { asn1_parser_t *parser; chunk_t object; int objectID; public_key_t *key = NULL; key_type_t type = KEY_ANY; parser = asn1_parser_create(pkinfoObjects, blob); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM: { int oid = asn1_parse_algorithmIdentifier(object, parser->get_level(parser)+1, NULL); if (oid == OID_RSA_ENCRYPTION || oid == OID_RSAES_OAEP) { type = KEY_RSA; } else if (oid == OID_EC_PUBLICKEY) { /* we need the whole subjectPublicKeyInfo for EC public keys */ key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER, blob, BUILD_END); goto end; } else { /* key type not supported */ goto end; } break; } case PKINFO_SUBJECT_PUBLIC_KEY: if (object.len > 0 && *object.ptr == 0x00) { /* skip initial bit string octet defining 0 unused bits */ object = chunk_skip(object, 1); } DBG2(DBG_ASN, "-- > --"); key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type, BUILD_BLOB_ASN1_DER, object, BUILD_END); DBG2(DBG_ASN, "-- < --"); break; } } end: parser->destroy(parser); return key; }
static void run_parser_test(const asn1Object_t *objects, int id, asn1_test_t *test) { asn1_parser_t *parser; chunk_t object; int objectID, count = 0; bool success; parser = asn1_parser_create(objects, test->blob); while (parser->iterate(parser, &objectID, &object)) { if (objectID == id) { count++; } } success = parser->success(parser); parser->destroy(parser); ck_assert(success == test->success && count == test->count); }
/** * Load an encrypted private key from an ASN.1 encoded blob * Schemes per PKCS#5 (RFC 2898) */ static private_key_t *parse_encrypted_private_key(chunk_t blob) { asn1_parser_t *parser; chunk_t object; int objectID; private_key_t *key = NULL; pkcs5_t *pkcs5 = NULL; parser = asn1_parser_create(encryptedPKIObjects, blob); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case EPKINFO_ENCRYPTION_ALGORITHM: { pkcs5 = pkcs5_from_algorithmIdentifier(object, parser->get_level(parser) + 1); if (!pkcs5) { goto end; } break; } case EPKINFO_ENCRYPTED_DATA: { key = decrypt_private_key(pkcs5, object); break; } } } end: DESTROY_IF(pkcs5); parser->destroy(parser); return key; }
/** * Load a RSA private key from a ASN1 encoded blob. */ static private_key_t *parse_rsa_private_key(chunk_t blob) { chunk_t n, e, d, p, q, exp1, exp2, coeff; asn1_parser_t *parser; chunk_t object; int objectID ; bool success = FALSE; parser = asn1_parser_create(privkeyObjects, blob); parser->set_flags(parser, FALSE, TRUE); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case PRIV_KEY_VERSION: if (object.len > 0 && *object.ptr != 0) { DBG1(DBG_ASN, "PKCS#1 private key format is not version 1"); goto end; } break; case PRIV_KEY_MODULUS: n = object; break; case PRIV_KEY_PUB_EXP: e = object; break; case PRIV_KEY_PRIV_EXP: d = object; break; case PRIV_KEY_PRIME1: p = object; break; case PRIV_KEY_PRIME2: q = object; break; case PRIV_KEY_EXP1: exp1 = object; break; case PRIV_KEY_EXP2: exp2 = object; break; case PRIV_KEY_COEFF: coeff = object; break; } } success = parser->success(parser); end: parser->destroy(parser); if (!success) { return NULL; } return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_RSA_PRIV_EXP, d, BUILD_RSA_PRIME1, p, BUILD_RSA_PRIME2, q, BUILD_RSA_EXP1, exp1, BUILD_RSA_EXP2, exp2, BUILD_RSA_COEFF, coeff, BUILD_END); }
/** * Load a generic private key from an ASN.1 encoded blob */ static private_key_t *parse_private_key(chunk_t blob) { asn1_parser_t *parser; chunk_t object, params = chunk_empty; int objectID; private_key_t *key = NULL; key_type_t type = KEY_ANY; builder_part_t part = BUILD_BLOB_ASN1_DER; parser = asn1_parser_create(pkinfoObjects, blob); parser->set_flags(parser, FALSE, TRUE); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case PKINFO_PRIVATE_KEY_ALGORITHM: { int oid = asn1_parse_algorithmIdentifier(object, parser->get_level(parser) + 1, ¶ms); switch (oid) { case OID_RSASSA_PSS: /* TODO: parameters associated with such keys should be * treated as restrictions later when signing (the type * itself is already a restriction). However, the * builders currently don't expect any parameters for * RSA keys (we also only pass along the params, not the * exact type, so we'd have to guess that params * indicate RSA/PSS, but they are optional so that won't * work for keys without specific restrictions) */ params = chunk_empty; /* fall-through */ case OID_RSA_ENCRYPTION: type = KEY_RSA; break; case OID_EC_PUBLICKEY: type = KEY_ECDSA; break; case OID_ED25519: type = KEY_ED25519; part = BUILD_EDDSA_PRIV_ASN1_DER; break; case OID_ED448: type = KEY_ED448; part = BUILD_EDDSA_PRIV_ASN1_DER; break; default: /* key type not supported */ goto end; } break; } case PKINFO_PRIVATE_KEY: { DBG2(DBG_ASN, "-- > --"); if (params.ptr) { key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, BUILD_BLOB_ALGID_PARAMS, params, part, object, BUILD_END); } else { key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, part, object, BUILD_END); } DBG2(DBG_ASN, "-- < --"); break; } } } end: parser->destroy(parser); return key; }
/** * Parse a PKCS#7 envelopedData object */ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, chunk_t serialNumber, private_key_t *key) { asn1_parser_t *parser; chunk_t object; chunk_t iv = chunk_empty; chunk_t symmetric_key = chunk_empty; chunk_t encrypted_content = chunk_empty; crypter_t *crypter = NULL; int enc_alg = OID_UNKNOWN; int content_enc_alg = OID_UNKNOWN; int version; int objectID; bool success = FALSE; contentInfo_t cInfo = empty_contentInfo; *data = chunk_empty; if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) { goto failed; } if (cInfo.type != OID_PKCS7_ENVELOPED_DATA) { DBG1(DBG_LIB, "pkcs7 content type is not envelopedData"); goto failed; } parser = asn1_parser_create(envelopedDataObjects, cInfo.content); parser->set_top_level(parser, 2); while (parser->iterate(parser, &objectID, &object)) { u_int level = parser->get_level(parser); switch (objectID) { case PKCS7_ENVELOPED_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); if (version != 0) { DBG1(DBG_LIB, "envelopedData version is not 0"); goto end; } break; case PKCS7_RECIPIENT_INFO_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); if (version != 0) { DBG1(DBG_LIB, "recipient info version is not 0"); goto end; } break; case PKCS7_ISSUER: { identification_t *issuer = identification_create_from_encoding( ID_DER_ASN1_DN, object); DBG2(DBG_LIB, " \"%Y\"", issuer); issuer->destroy(issuer); break; } case PKCS7_SERIAL_NUMBER: if (!chunk_equals(serialNumber, object)) { DBG1(DBG_LIB, "serial numbers do not match"); goto end; } break; case PKCS7_ENCRYPTION_ALG: enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); if (enc_alg != OID_RSA_ENCRYPTION) { DBG1(DBG_LIB, "only rsa encryption supported"); goto end; } break; case PKCS7_ENCRYPTED_KEY: if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) { DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); goto end; } DBG4(DBG_LIB, "symmetric key %B", &symmetric_key); break; case PKCS7_CONTENT_TYPE: if (asn1_known_oid(object) != OID_PKCS7_DATA) { DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); goto end; } break; case PKCS7_CONTENT_ENC_ALGORITHM: content_enc_alg = asn1_parse_algorithmIdentifier(object, level, &iv); if (content_enc_alg == OID_UNKNOWN) { DBG1(DBG_LIB, "unknown content encryption algorithm"); goto end; } if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV")) { DBG1(DBG_LIB, "IV could not be parsed"); goto end; } break; case PKCS7_ENCRYPTED_CONTENT: encrypted_content = object; break; } } success = parser->success(parser); end: parser->destroy(parser); if (!success) { goto failed; } success = FALSE; /* decrypt the content */ { encryption_algorithm_t alg; size_t key_size; crypter_t *crypter; alg = encryption_algorithm_from_oid(content_enc_alg, &key_size); if (alg == ENCR_UNDEFINED) { DBG1(DBG_LIB, "unsupported content encryption algorithm"); goto failed; } crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); if (crypter == NULL) { DBG1(DBG_LIB, "crypter %N not available", encryption_algorithm_names, alg); goto failed; } if (symmetric_key.len != crypter->get_key_size(crypter)) { DBG1(DBG_LIB, "symmetric key length %d is wrong", symmetric_key.len); goto failed; } if (iv.len != crypter->get_iv_size(crypter)) { DBG1(DBG_LIB, "IV length %d is wrong", iv.len); goto failed; } crypter->set_key(crypter, symmetric_key); crypter->decrypt(crypter, encrypted_content, iv, data); DBG4(DBG_LIB, "decrypted content with padding: %B", data); } /* remove the padding */ { u_char *pos = data->ptr + data->len - 1; u_char pattern = *pos; size_t padding = pattern; if (padding > data->len) { DBG1(DBG_LIB, "padding greater than data length"); goto failed; } data->len -= padding; while (padding-- > 0) { if (*pos-- != pattern) { DBG1(DBG_LIB, "wrong padding pattern"); goto failed; } } } success = TRUE; failed: DESTROY_IF(crypter); chunk_clear(&symmetric_key); if (!success) { free(data->ptr); } return success; }
/** * Parse a PKCS#7 signedData object */ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, linked_list_t *certs, chunk_t *attributes, certificate_t *cacert) { asn1_parser_t *parser; chunk_t object; int digest_alg = OID_UNKNOWN; int enc_alg = OID_UNKNOWN; int signerInfos = 0; int version; int objectID; bool success = FALSE; contentInfo_t cInfo = empty_contentInfo; chunk_t encrypted_digest = chunk_empty; if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) { return FALSE; } if (cInfo.type != OID_PKCS7_SIGNED_DATA) { DBG1(DBG_LIB, "pkcs7 content type is not signedData"); return FALSE; } parser = asn1_parser_create(signedDataObjects, cInfo.content); parser->set_top_level(parser, 2); while (parser->iterate(parser, &objectID, &object)) { u_int level = parser->get_level(parser); switch (objectID) { case PKCS7_SIGNED_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); break; case PKCS7_DIGEST_ALG: digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case PKCS7_SIGNED_CONTENT_INFO: if (data != NULL) { pkcs7_parse_contentInfo(object, level, data); } break; case PKCS7_SIGNED_CERT: { certificate_t *cert; DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB_ASN1_DER, object, BUILD_END); if (cert) { certs->insert_last(certs, cert); } } break; case PKCS7_SIGNER_INFO: signerInfos++; DBG2(DBG_LIB, " signer #%d", signerInfos); break; case PKCS7_SIGNER_INFO_VERSION: version = object.len ? (int)*object.ptr : 0; DBG2(DBG_LIB, " v%d", version); break; case PKCS7_SIGNED_ISSUER: { identification_t *issuer = identification_create_from_encoding( ID_DER_ASN1_DN, object); DBG2(DBG_LIB, " \"%Y\"", issuer); issuer->destroy(issuer); break; } case PKCS7_AUTH_ATTRIBUTES: if (attributes != NULL) { *attributes = object; *attributes->ptr = ASN1_SET; } break; case PKCS7_DIGEST_ALGORITHM: digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case PKCS7_DIGEST_ENC_ALGORITHM: enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case PKCS7_ENCRYPTED_DIGEST: encrypted_digest = object; } } success = parser->success(parser); parser->destroy(parser); if (!success) { return FALSE; } /* check the signature only if a cacert is available */ if (cacert != NULL) { public_key_t *key; signature_scheme_t scheme; scheme = signature_scheme_from_oid(digest_alg); if (scheme == SIGN_UNKNOWN) { DBG1(DBG_LIB, "unsupported signature scheme"); return FALSE; } if (signerInfos == 0) { DBG1(DBG_LIB, "no signerInfo object found"); return FALSE; } else if (signerInfos > 1) { DBG1(DBG_LIB, "more than one signerInfo object found"); return FALSE; } if (attributes->ptr == NULL) { DBG1(DBG_LIB, "no authenticatedAttributes object found"); return FALSE; } if (enc_alg != OID_RSA_ENCRYPTION) { DBG1(DBG_LIB, "only RSA digest encryption supported"); return FALSE; } /* verify the signature */ key = cacert->get_public_key(cacert); if (key == NULL) { DBG1(DBG_LIB, "no public key found in CA certificate"); return FALSE; } if (key->verify(key, scheme, *attributes, encrypted_digest)) { DBG2(DBG_LIB, "signature is valid"); } else { DBG1(DBG_LIB, "invalid signature"); success = FALSE; } key->destroy(key); } return success; }