Ejemplo n.º 1
0
END_TEST

/*******************************************************************************
 * parse_algorithm_identifier
 */

START_TEST(test_asn1_parse_algorithmIdentifier)
{
	typedef struct {
		int alg;
		bool empty;
		chunk_t parameters;
	} testdata_t;

	testdata_t test[] = {
		{ OID_ECDSA_WITH_SHA1, TRUE,  chunk_empty },
		{ OID_SHA1_WITH_RSA,   TRUE,  chunk_from_chars(0x05, 0x00) },
		{ OID_3DES_EDE_CBC,    FALSE, chunk_from_chars(0x04, 0x01, 0xaa) },
		{ OID_PBKDF2,          FALSE, chunk_from_chars(0x30, 0x01, 0xaa) }
	};

	chunk_t algid, parameters;
	int i, alg;

	for (i = 0; i < countof(test); i++)
	{
		algid = asn1_wrap(ASN1_SEQUENCE, "mc",
					 asn1_build_known_oid(test[i].alg), test[i].parameters);
		parameters = chunk_empty;
		if (i == 2)
		{
			alg = asn1_parse_algorithmIdentifier(algid, 0, NULL);
		}
		else
		{
			alg = asn1_parse_algorithmIdentifier(algid, 0, &parameters);
			if (test[i].empty)
			{
				ck_assert(parameters.len == 0 && parameters.ptr == NULL);
			}
				else
			{
				ck_assert(chunk_equals(parameters, test[i].parameters));
			}
		}
		ck_assert(alg == test[i].alg);
		chunk_free(&algid);
	}
}
Ejemplo n.º 2
0
/**
 * 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, &params);

				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;
}
Ejemplo n.º 3
0
/**
 * 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;
}
Ejemplo n.º 4
0
/**
 * 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, &params);

				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;
}
Ejemplo n.º 5
0
/**
 * 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;
}
Ejemplo n.º 6
0
/**
 * 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;
}
Ejemplo n.º 7
0
/**
 * Encode the public key as Base64 encoded SSH key blob
 */
static bool build_public_key(chunk_t *encoding, va_list args)
{
	bio_writer_t *writer;
	chunk_t n, e;

	if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n,
						   CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END))
	{
		writer = bio_writer_create(0);
		writer->write_data32(writer, chunk_from_str("ssh-rsa"));

		writer->write_data32(writer, e);
		writer->write_data32(writer, n);
		*encoding = chunk_to_base64(writer->get_buf(writer), NULL);
		writer->destroy(writer);
		return TRUE;
	}
	else if (cred_encoding_args(args, CRED_PART_EDDSA_PUB_ASN1_DER, &n,
								CRED_PART_END))
	{
		chunk_t alg;
		char *prefix;
		int oid;

		/* parse subjectPublicKeyInfo */
		if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE)
		{
			return FALSE;
		}
		oid = asn1_parse_algorithmIdentifier(n, 1, NULL);
		switch (oid)
		{
			case OID_ED25519:
				prefix = "ssh-ed25519";
				break;
			case OID_ED448:
				prefix = "ssh-ed448";
				break;
			default:
				return FALSE;
		}
		if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE ||
			asn1_unwrap(&n, &n) != ASN1_BIT_STRING || !n.len)
		{
			return FALSE;
		}
		writer = bio_writer_create(0);
		writer->write_data32(writer, chunk_from_str(prefix));
		writer->write_data32(writer, chunk_skip(n, 1));
		*encoding = chunk_to_base64(writer->get_buf(writer), NULL);
		writer->destroy(writer);
		return TRUE;
	}
	else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n,
								CRED_PART_END))
	{
		chunk_t params, alg, q;
		int oid;

		/* parse subjectPublicKeyInfo */
		if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE)
		{
			return FALSE;
		}
		oid = asn1_parse_algorithmIdentifier(n, 1, &params);
		if (oid != OID_EC_PUBLICKEY ||
			asn1_unwrap(&params, &params) != ASN1_OID)
		{
			return FALSE;
		}
		oid = asn1_known_oid(params);
		if (oid == OID_UNKNOWN)
		{
			return FALSE;
		}
		if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE ||
			asn1_unwrap(&n, &q) != ASN1_BIT_STRING)
		{
			return FALSE;
		}
		writer = bio_writer_create(0);
		write_ec_identifier(writer, ECDSA_PREFIX, oid, params);
		write_ec_identifier(writer, "", oid, params);

		q = chunk_skip_zero(q);
		writer->write_data32(writer, q);
		*encoding = chunk_to_base64(writer->get_buf(writer), NULL);
		writer->destroy(writer);
		return TRUE;
	}
	return FALSE;
}