int ecc_der_decode_public_key_no_copy()

in core/asn1/ecc_der_util.c [608:715]


int ecc_der_decode_public_key_no_copy (const uint8_t *der, size_t length, const uint8_t **pub_key)
{
	const uint8_t *pos = der;
	size_t type_len;
	size_t oid_len;
	size_t key_len;
	const uint8_t *oid;
	int status;

	if ((der == NULL) || (pub_key == NULL)) {
		return ECC_DER_UTIL_INVALID_ARGUMENT;
	}

	status = ecc_der_get_next_tag (0x30, &pos, &length, &type_len);
	if (status != 0) {
		return status;
	}

	status = ecc_der_get_next_tag (0x30, &pos, &length, &type_len);
	if (status != 0) {
		return status;
	}

	status = ecc_der_get_next_tag (0x06, &pos, &length, &type_len);
	if (status != 0) {
		return status;
	}

	if (((type_len != sizeof (ECC_DER_EC_PUBLIC_KEY_OID)) ||
		(memcmp (pos, ECC_DER_EC_PUBLIC_KEY_OID, type_len) != 0))) {
		return ECC_DER_UTIL_UNSUPPORTED_ALGORITHM;
	}

	pos += type_len;
	length -= type_len;

	status = ecc_der_get_next_tag (0x06, &pos, &length, &type_len);
	if (status != 0) {
		return status;
	}

	/* Save the curve OID so we can compare against it once we know the key length. */
	oid_len = type_len;
	oid = pos;

	pos += type_len;
	length -= type_len;

	status = ecc_der_get_next_tag (0x03, &pos, &length, &type_len);
	if (status != 0) {
		return status;
	}

	key_len = (type_len - 2) / 2;

	switch (key_len) {
		case ECC_KEY_LENGTH_256:
			if ((oid_len != sizeof (ECC_DER_P256_OID)) ||
				(memcmp (oid, ECC_DER_P256_OID, oid_len) != 0)) {
				return ECC_DER_UTIL_UNSUPPORTED_CURVE;
			}
			break;

#if ECC_MAX_KEY_LENGTH >= ECC_KEY_LENGTH_384
		case ECC_KEY_LENGTH_384:
			if ((oid_len != sizeof (ECC_DER_P384_OID)) ||
				(memcmp (oid, ECC_DER_P384_OID, oid_len) != 0)) {
				return ECC_DER_UTIL_UNSUPPORTED_CURVE;
			}
			break;
#endif

#if ECC_MAX_KEY_LENGTH >= ECC_KEY_LENGTH_521
		case ECC_KEY_LENGTH_521:
			if ((oid_len != sizeof (ECC_DER_P521_OID)) ||
				(memcmp (oid, ECC_DER_P521_OID, oid_len) != 0)) {
				return ECC_DER_UTIL_UNSUPPORTED_CURVE;
			}
			break;
#endif

		default:
			return ECC_DER_UTIL_UNSUPPORTED_KEY_LENGTH;
	}

	/* Skip over the leading zero in the public key bit string. */
	pos++;
	type_len--;

	/* Confirm a valid ECPoint format for the public key. */
	switch (pos[0]) {
		case 0x02:
		case 0x03:
			/* Compressed ECPoint */
			break;

		case 0x04:
			/* Uncompressed ECPoint */
			break;

		default:
			return ECC_DER_UTIL_INVALID_ECPOINT;
	}

	*pub_key = pos;

	return type_len;
}