mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-12 01:53:07 +03:00
Added SAN ("Subject Alternative Name" support
git-svn-id: svn://svn.code.sf.net/p/axtls/code/trunk@159 9a5d90b5-6617-0410-8a86-bb477d3ed2e3
This commit is contained in:
54
ssl/asn1.c
54
ssl/asn1.c
@ -42,6 +42,7 @@
|
||||
|
||||
#define SIG_OID_PREFIX_SIZE 8
|
||||
#define SIG_IIS6_OID_SIZE 5
|
||||
#define SIG_SUBJECT_ALT_NAME_SIZE 3
|
||||
|
||||
/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */
|
||||
static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] =
|
||||
@ -54,6 +55,11 @@ static const uint8_t sig_iis6_oid[SIG_IIS6_OID_SIZE] =
|
||||
0x2b, 0x0e, 0x03, 0x02, 0x1d
|
||||
};
|
||||
|
||||
static const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] =
|
||||
{
|
||||
0x55, 0x1d, 0x11
|
||||
};
|
||||
|
||||
/* CN, O, OU */
|
||||
static const uint8_t g_dn_types[] = { 3, 10, 11 };
|
||||
|
||||
@ -284,6 +290,7 @@ static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)
|
||||
|
||||
/* some certs have this awful crud in them for some reason */
|
||||
if (buf[*offset] != ASN1_PRINTABLE_STR &&
|
||||
buf[*offset] != ASN1_PRINTABLE_STR2 &&
|
||||
buf[*offset] != ASN1_TELETEX_STR &&
|
||||
buf[*offset] != ASN1_IA5_STR &&
|
||||
buf[*offset] != ASN1_UNICODE_STR)
|
||||
@ -471,7 +478,52 @@ int asn1_compare_dn(char * const dn1[], char * const dn2[])
|
||||
return 0; /* all good */
|
||||
}
|
||||
|
||||
#endif
|
||||
int asn1_find_oid(const uint8_t* cert, int* offset,
|
||||
const uint8_t* oid, int oid_length)
|
||||
{
|
||||
int seqlen;
|
||||
if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0)
|
||||
{
|
||||
int end = *offset + seqlen;
|
||||
|
||||
while (*offset < end)
|
||||
{
|
||||
int type = cert[(*offset)++];
|
||||
int length = get_asn1_length(cert, offset);
|
||||
int noffset = *offset + length;
|
||||
|
||||
if (type == ASN1_SEQUENCE)
|
||||
{
|
||||
type = cert[(*offset)++];
|
||||
length = get_asn1_length(cert, offset);
|
||||
|
||||
if (type == ASN1_OID && length == oid_length &&
|
||||
memcmp(cert + *offset, oid, oid_length) == 0)
|
||||
{
|
||||
*offset += oid_length;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
*offset = noffset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asn1_find_subjectaltname(const uint8_t* cert, int offset)
|
||||
{
|
||||
if (asn1_find_oid(cert, &offset, sig_subject_alt_name,
|
||||
SIG_SUBJECT_ALT_NAME_SIZE))
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||
|
||||
/**
|
||||
* Read the signature type of the certificate. We only support RSA-MD5 and
|
||||
|
@ -68,6 +68,7 @@ struct _x509_ctx
|
||||
{
|
||||
char *ca_cert_dn[X509_NUM_DN_TYPES];
|
||||
char *cert_dn[X509_NUM_DN_TYPES];
|
||||
char **subject_alt_dnsnames;
|
||||
time_t not_before;
|
||||
time_t not_after;
|
||||
uint8_t *signature;
|
||||
@ -104,16 +105,22 @@ const char * x509_display_error(int error);
|
||||
#define ASN1_BIT_STRING 0x03
|
||||
#define ASN1_OCTET_STRING 0x04
|
||||
#define ASN1_NULL 0x05
|
||||
#define ASN1_PRINTABLE_STR2 0x0C
|
||||
#define ASN1_OID 0x06
|
||||
#define ASN1_PRINTABLE_STR2 0x0C
|
||||
#define ASN1_PRINTABLE_STR 0x13
|
||||
#define ASN1_TELETEX_STR 0x14
|
||||
#define ASN1_IA5_STR 0x16
|
||||
#define ASN1_UTC_TIME 0x17
|
||||
#define ASN1_UNICODE_STR 0x1e
|
||||
#define ASN1_SEQUENCE 0x30
|
||||
#define ASN1_CONTEXT_DNSNAME 0x82
|
||||
#define ASN1_SET 0x31
|
||||
#define ASN1_V3_DATA 0xa3
|
||||
#define ASN1_IMPLICIT_TAG 0x80
|
||||
#define ASN1_CONTEXT_DNSNAME 0x82
|
||||
#define ASN1_EXPLICIT_TAG 0xa0
|
||||
#define ASN1_V3_DATA 0xa3
|
||||
|
||||
#define SIG_TYPE_MD2 0x02
|
||||
#define SIG_TYPE_MD5 0x04
|
||||
@ -130,8 +137,9 @@ int asn1_name(const uint8_t *cert, int *offset, char *dn[]);
|
||||
int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||
int asn1_find_subjectaltname(const uint8_t* cert, int offset);
|
||||
int asn1_compare_dn(char * const dn1[], char * const dn2[]);
|
||||
#endif
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||
int asn1_signature_type(const uint8_t *cert,
|
||||
int *offset, X509_CTX *x509_ctx);
|
||||
|
||||
|
17
ssl/ssl.h
17
ssl/ssl.h
@ -384,6 +384,23 @@ EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve a Subject Alternative DNSName
|
||||
*
|
||||
* When a handshake is complete and a certificate has been exchanged, then the
|
||||
* details of the remote certificate can be retrieved.
|
||||
*
|
||||
* This will usually be used by a client to check that the server's common
|
||||
* name matches the URL.
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param index [in] The index of the DNS name to retrieve.
|
||||
* @return The appropriate string (or null if not defined)
|
||||
* @note Verification build mode must be enabled.
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex);
|
||||
|
||||
/**
|
||||
* @brief Force the client to perform its handshake again.
|
||||
*
|
||||
|
34
ssl/tls1.c
34
ssl/tls1.c
@ -419,6 +419,7 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Retrieve an X.509 distinguished name component
|
||||
*/
|
||||
@ -452,7 +453,27 @@ EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Retrieve a "Subject Alternative Name" from a v3 certificate
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl,
|
||||
int dnsindex)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < dnsindex; ++i)
|
||||
{
|
||||
if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ssl->x509_ctx->subject_alt_dnsnames[dnsindex];
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||
|
||||
/*
|
||||
* Find an ssl object based on the client's file descriptor.
|
||||
@ -879,7 +900,6 @@ static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt)
|
||||
|
||||
return (void *)aes_ctx;
|
||||
}
|
||||
break;
|
||||
|
||||
case SSL_RC4_128_MD5:
|
||||
#endif
|
||||
@ -889,7 +909,6 @@ static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt)
|
||||
RC4_setup(rc4_ctx, key, 16);
|
||||
return (void *)rc4_ctx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL; /* its all gone wrong */
|
||||
@ -1505,7 +1524,7 @@ void disposable_free(SSL *ssl)
|
||||
{
|
||||
if (ssl->dc)
|
||||
{
|
||||
free(ssl->dc->key_block);
|
||||
free(ssl->dc->key_block);
|
||||
memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX));
|
||||
free(ssl->dc);
|
||||
ssl->dc = NULL;
|
||||
@ -2045,12 +2064,19 @@ EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component)
|
||||
{
|
||||
printf(unsupported_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index)
|
||||
{
|
||||
printf(unsupported_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||
|
||||
#endif /* CONFIG_BINDINGS */
|
||||
|
57
ssl/x509.c
57
ssl/x509.c
@ -147,7 +147,53 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
|
||||
x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);
|
||||
}
|
||||
|
||||
offset = end_tbs; /* skip the v3 data */
|
||||
if (cert[offset] == ASN1_V3_DATA)
|
||||
{
|
||||
int suboffset;
|
||||
|
||||
++offset;
|
||||
get_asn1_length(cert, &offset);
|
||||
|
||||
if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)
|
||||
{
|
||||
if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)
|
||||
{
|
||||
int altlen;
|
||||
|
||||
if ((altlen = asn1_next_obj(cert,
|
||||
&suboffset, ASN1_SEQUENCE)) > 0)
|
||||
{
|
||||
int endalt = suboffset + altlen;
|
||||
int totalnames = 0;
|
||||
|
||||
while (suboffset < endalt)
|
||||
{
|
||||
int type = cert[suboffset++];
|
||||
int dnslen = get_asn1_length(cert, &suboffset);
|
||||
|
||||
if (type == ASN1_CONTEXT_DNSNAME)
|
||||
{
|
||||
x509_ctx->subject_alt_dnsnames = (char**)
|
||||
realloc(x509_ctx->subject_alt_dnsnames,
|
||||
(totalnames + 2) * sizeof(char*));
|
||||
x509_ctx->subject_alt_dnsnames[totalnames] =
|
||||
(char*)malloc(dnslen + 1);
|
||||
x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;
|
||||
memcpy(x509_ctx->subject_alt_dnsnames[totalnames],
|
||||
cert + suboffset, dnslen);
|
||||
x509_ctx->subject_alt_dnsnames[
|
||||
totalnames][dnslen] = 0;
|
||||
++totalnames;
|
||||
}
|
||||
|
||||
suboffset += dnslen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset = end_tbs; /* skip the rest of v3 data */
|
||||
if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) ||
|
||||
asn1_signature(cert, &offset, x509_ctx))
|
||||
goto end_cert;
|
||||
@ -188,6 +234,7 @@ void x509_free(X509_CTX *x509_ctx)
|
||||
free(x509_ctx->cert_dn[i]);
|
||||
}
|
||||
|
||||
|
||||
free(x509_ctx->signature);
|
||||
|
||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||
@ -195,6 +242,14 @@ void x509_free(X509_CTX *x509_ctx)
|
||||
{
|
||||
bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);
|
||||
}
|
||||
|
||||
if (x509_ctx->subject_alt_dnsnames)
|
||||
{
|
||||
for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)
|
||||
free(x509_ctx->subject_alt_dnsnames[i]);
|
||||
|
||||
free(x509_ctx->subject_alt_dnsnames);
|
||||
}
|
||||
#endif
|
||||
|
||||
RSA_free(x509_ctx->rsa_ctx);
|
||||
|
Reference in New Issue
Block a user