END_TEST /******************************************************************************* * parse_simple_object */ START_TEST(test_asn1_parse_simple_object) { typedef struct { bool res; int type; chunk_t chunk; } testdata_t; testdata_t test[] = { { FALSE, 0x04, chunk_from_chars(0x04) }, { FALSE, 0x04, chunk_from_chars(0x02, 0x01, 0x55) }, { FALSE, 0x04, chunk_from_chars(0x04, 0x01) }, { TRUE, 0x04, chunk_from_chars(0x04, 0x01, 0x55) }, { TRUE, 0x06, chunk_from_chars(0x06, 0x02, 0x55, 0x03) }, { TRUE, 0x06, chunk_from_chars(0x06, 0x00) }, { TRUE, 0x13, chunk_from_chars(0x13, 0x01, 0x55), } }; int i; bool res; for (i = 0; i < countof(test); i++) { res = asn1_parse_simple_object(&test[i].chunk, test[i].type, 0, "test"); ck_assert(res == test[i].res); if (res && test[i].chunk.len) { ck_assert(*test[i].chunk.ptr == 0x55); } } }
/** * Extract and store an attribute */ static bool extract_attribute(int oid, chunk_t object, u_int level, scep_attributes_t *attrs) { asn1_t type = ASN1_EOC; const char *name = "none"; switch (oid) { case OID_PKCS9_CONTENT_TYPE: type = ASN1_OID; name = "contentType"; break; case OID_PKCS9_SIGNING_TIME: type = ASN1_UTCTIME; name = "signingTime"; break; case OID_PKCS9_MESSAGE_DIGEST: type = ASN1_OCTET_STRING; name = "messageDigest"; break; case OID_PKI_MESSAGE_TYPE: type = ASN1_PRINTABLESTRING; name = "messageType"; break; case OID_PKI_STATUS: type = ASN1_PRINTABLESTRING; name = "pkiStatus"; break; case OID_PKI_FAIL_INFO: type = ASN1_PRINTABLESTRING; name = "failInfo"; break; case OID_PKI_SENDER_NONCE: type = ASN1_OCTET_STRING; name = "senderNonce"; break; case OID_PKI_RECIPIENT_NONCE: type = ASN1_OCTET_STRING; name = "recipientNonce"; break; case OID_PKI_TRANS_ID: type = ASN1_PRINTABLESTRING; name = "transID"; break; default: break; } if (type == ASN1_EOC) return TRUE; if (!asn1_parse_simple_object(&object, type, level+1, name)) return FALSE; switch (oid) { case OID_PKCS9_CONTENT_TYPE: break; case OID_PKCS9_SIGNING_TIME: break; case OID_PKCS9_MESSAGE_DIGEST: break; case OID_PKI_MESSAGE_TYPE: { scep_msg_t m; for (m = SCEP_CertRep_MSG; m < SCEP_Unknown_MSG; m++) { if (strncmp(msgType_values[m], object.ptr, object.len) == 0) attrs->msgType = m; } DBG(DBG_CONTROL, DBG_log("messageType: %s", msgType_names[attrs->msgType]) ) } break; case OID_PKI_STATUS: { pkiStatus_t s; for (s = SCEP_SUCCESS; s < SCEP_UNKNOWN; s++) { if (strncmp(pkiStatus_values[s], object.ptr, object.len) == 0) attrs->pkiStatus = s; } DBG(DBG_CONTROL, DBG_log("pkiStatus: %s", pkiStatus_names[attrs->pkiStatus]) ) } break; case OID_PKI_FAIL_INFO: if (object.len == 1 && *object.ptr >= '0' && *object.ptr <= '4') { attrs->failInfo = (failInfo_t)(*object.ptr - '0'); } if (attrs->failInfo != SCEP_unknown_REASON) plog("failInfo: %s", failInfo_reasons[attrs->failInfo]); break; case OID_PKI_SENDER_NONCE: attrs->senderNonce = object; break; case OID_PKI_RECIPIENT_NONCE: attrs->recipientNonce = object; break; case OID_PKI_TRANS_ID: attrs->transID = object; } return TRUE; }
/** * 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; }