/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file x509_decode_public_key_from_certificate.c
ASN.1 DER/X.509, decode a SubjectPublicKeyInfo
*/
#ifdef LTC_DER
/* Check if it looks like a SubjectPublicKeyInfo */
#define LOOKS_LIKE_SPKI(l) ((l) != NULL) \
&& ((l)->type == LTC_ASN1_SEQUENCE) \
&& ((l)->child != NULL) \
&& ((l)->child->type == LTC_ASN1_OBJECT_IDENTIFIER) \
&& ((l)->next != NULL) \
&& ((l)->next->type == LTC_ASN1_BIT_STRING)
/**
DER decode a X.509 certificate and return the SubjectPublicKeyInfo
@param in The input buffer
@param inlen The length of the input buffer
@param out [out] A pointer to the decoded linked list (you take ownership of this one and
`der_free_sequence_flexi()` it when you're done)
@param spki [out] A pointer to the SubjectPublicKeyInfo
@return CRYPT_OK on success, CRYPT_NOP if no SubjectPublicKeyInfo was found, another error if decoding failed
*/
int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki)
{
int err;
unsigned long tmp_inlen, n, element_is_spki;
ltc_asn1_list *decoded_list = NULL, *l;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen != 0);
tmp_inlen = inlen;
if ((err = der_decode_sequence_flexi(in, &tmp_inlen, &decoded_list)) == CRYPT_OK) {
l = decoded_list;
err = CRYPT_NOP;
/* Move 2 levels up in the tree
SEQUENCE
SEQUENCE
...
*/
if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
l = l->child;
if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) {
/* TBSCertificate ::= SEQUENCE {
* version [0] EXPLICIT Version DEFAULT v1,
* serialNumber CertificateSerialNumber,
* signature AlgorithmIdentifier,
* issuer Name,
* validity Validity,
* subject Name,
* subjectPublicKeyInfo SubjectPublicKeyInfo,
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version MUST be v2 or v3
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version MUST be v2 or v3
* extensions [3] EXPLICIT Extensions OPTIONAL
* -- If present, version MUST be v3
* }
*/
l = l->child;
/* `l` points now either to 'version' or 'serialNumber', depending on
* whether 'version' is included or defaults to 'v1'.
* 'version' is represented as a LTC_ASN1_CUSTOM_TYPE
* 'serialNumber' is represented as an LTC_ASN1_INTEGER
* Decide now whether to move 5 or 6 elements forward until
* `l` should point to subjectPublicKeyInfo.
*/
if (l->type == LTC_ASN1_CUSTOM_TYPE)
element_is_spki = 6;
else
element_is_spki = 5;
for (n = 0; n < element_is_spki && l; ++n) {
l = l->next;
}
/* The additional check for l->data is there to make sure
* we won't try to decode a list that has been 'shrunk'
*/
if ((l != NULL)
&& (l->type == LTC_ASN1_SEQUENCE)
&& (l->data != NULL)
&& LOOKS_LIKE_SPKI(l->child)) {
*out = decoded_list;
*spki = l;
return CRYPT_OK;
}
}
}
}
if (decoded_list) der_free_sequence_flexi(decoded_list);
return err;
}
#endif