Exemple #1
0
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);
		}
	}
}
Exemple #2
0
/**
 * 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;
}