mirror of
https://github.com/esp8266/Arduino.git
synced 2025-10-15 11:26:40 +03:00
* Basic constraint functionality added.
git-svn-id: svn://svn.code.sf.net/p/axtls/code/trunk@273 9a5d90b5-6617-0410-8a86-bb477d3ed2e3
This commit is contained in:
committed by
Ivan Grokhotkov
parent
2213f30449
commit
a2c7c7e40a
@@ -41,6 +41,11 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* some bool types - just make life easier */
|
||||||
|
typedef char bool;
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
typedef UINT8 uint8_t;
|
typedef UINT8 uint8_t;
|
||||||
typedef INT8 int8_t;
|
typedef INT8 int8_t;
|
||||||
|
174
ssl/asn1.c
174
ssl/asn1.c
@@ -80,6 +80,16 @@ static const uint8_t sig_subject_alt_name[] =
|
|||||||
0x55, 0x1d, 0x11
|
0x55, 0x1d, 0x11
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint8_t sig_basic_constraints[] =
|
||||||
|
{
|
||||||
|
0x55, 0x1d, 0x13
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t sig_key_usage[] =
|
||||||
|
{
|
||||||
|
0x55, 0x1d, 0x0f
|
||||||
|
};
|
||||||
|
|
||||||
/* CN, O, OU, L, C, ST */
|
/* CN, O, OU, L, C, ST */
|
||||||
static const uint8_t g_dn_types[] = { 3, 10, 11, 7, 6, 8 };
|
static const uint8_t g_dn_types[] = { 3, 10, 11, 7, 6, 8 };
|
||||||
|
|
||||||
@@ -117,6 +127,7 @@ int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)
|
|||||||
{
|
{
|
||||||
if (buf[*offset] != obj_type)
|
if (buf[*offset] != obj_type)
|
||||||
return X509_NOT_OK;
|
return X509_NOT_OK;
|
||||||
|
|
||||||
(*offset)++;
|
(*offset)++;
|
||||||
return get_asn1_length(buf, offset);
|
return get_asn1_length(buf, offset);
|
||||||
}
|
}
|
||||||
@@ -141,12 +152,12 @@ int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)
|
|||||||
* Read an integer value for ASN.1 data
|
* Read an integer value for ASN.1 data
|
||||||
* Note: This function allocates memory which must be freed by the user.
|
* Note: This function allocates memory which must be freed by the user.
|
||||||
*/
|
*/
|
||||||
int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
|
int asn1_get_big_int(const uint8_t *buf, int *offset, uint8_t **object)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
|
if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)
|
||||||
goto end_int_array;
|
goto end_big_int;
|
||||||
|
|
||||||
if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */
|
if (len > 1 && buf[*offset] == 0x00) /* ignore the negative byte */
|
||||||
{
|
{
|
||||||
@@ -158,10 +169,93 @@ int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)
|
|||||||
memcpy(*object, &buf[*offset], len);
|
memcpy(*object, &buf[*offset], len);
|
||||||
*offset += len;
|
*offset += len;
|
||||||
|
|
||||||
end_int_array:
|
end_big_int:
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an integer value for ASN.1 data
|
||||||
|
*/
|
||||||
|
int asn1_get_int(const uint8_t *buf, int *offset, int32_t *val)
|
||||||
|
{
|
||||||
|
int res = X509_OK;
|
||||||
|
int len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0 ||
|
||||||
|
len > sizeof(int32_t))
|
||||||
|
{
|
||||||
|
res = X509_NOT_OK;
|
||||||
|
goto end_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
*val = 0;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
*val <<= 8;
|
||||||
|
*val |= buf[(*offset)++];
|
||||||
|
}
|
||||||
|
|
||||||
|
end_int:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an boolean value for ASN.1 data
|
||||||
|
*/
|
||||||
|
int asn1_get_bool(const uint8_t *buf, int *offset, bool *val)
|
||||||
|
{
|
||||||
|
int res = X509_OK;
|
||||||
|
|
||||||
|
if (asn1_next_obj(buf, offset, ASN1_BOOLEAN) != 1)
|
||||||
|
{
|
||||||
|
res = X509_NOT_OK;
|
||||||
|
goto end_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DER demands that "If the encoding represents the boolean value TRUE,
|
||||||
|
its single contents octet shall have all eight bits set to one."
|
||||||
|
Thus only 0 and 255 are valid encoded values. */
|
||||||
|
*val = buf[(*offset)++] == 0xFF;
|
||||||
|
|
||||||
|
end_bool:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an ASN.1 bit string into a 32 bit integer
|
||||||
|
*/
|
||||||
|
int asn1_get_bit_string_as_int(const uint8_t *buf, int *offset, uint32_t *val)
|
||||||
|
{
|
||||||
|
int res = X509_OK;
|
||||||
|
int len, i;
|
||||||
|
int ignore_bits;
|
||||||
|
|
||||||
|
if ((len = asn1_next_obj(buf, offset, ASN1_BIT_STRING)) < 0 || len > 5)
|
||||||
|
{
|
||||||
|
res = X509_NOT_OK;
|
||||||
|
goto end_bit_string_as_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* number of bits left unused in the final byte of content */
|
||||||
|
ignore_bits = buf[(*offset)++];
|
||||||
|
len--;
|
||||||
|
*val = 0;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
*val <<= 8;
|
||||||
|
*val |= buf[(*offset)++];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ignore_bits; i++)
|
||||||
|
{
|
||||||
|
*val >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_bit_string_as_int:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the RSA private key specifics from an ASN.1 encoded file
|
* Get all the RSA private key specifics from an ASN.1 encoded file
|
||||||
*/
|
*/
|
||||||
@@ -187,19 +281,19 @@ int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)
|
|||||||
/* Use the private key to mix up the RNG if possible. */
|
/* Use the private key to mix up the RNG if possible. */
|
||||||
RNG_custom_init(buf, len);
|
RNG_custom_init(buf, len);
|
||||||
|
|
||||||
mod_len = asn1_get_int(buf, &offset, &modulus);
|
mod_len = asn1_get_big_int(buf, &offset, &modulus);
|
||||||
pub_len = asn1_get_int(buf, &offset, &pub_exp);
|
pub_len = asn1_get_big_int(buf, &offset, &pub_exp);
|
||||||
priv_len = asn1_get_int(buf, &offset, &priv_exp);
|
priv_len = asn1_get_big_int(buf, &offset, &priv_exp);
|
||||||
|
|
||||||
if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
|
if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)
|
||||||
return X509_INVALID_PRIV_KEY;
|
return X509_INVALID_PRIV_KEY;
|
||||||
|
|
||||||
#ifdef CONFIG_BIGINT_CRT
|
#ifdef CONFIG_BIGINT_CRT
|
||||||
p_len = asn1_get_int(buf, &offset, &p);
|
p_len = asn1_get_big_int(buf, &offset, &p);
|
||||||
q_len = asn1_get_int(buf, &offset, &q);
|
q_len = asn1_get_big_int(buf, &offset, &q);
|
||||||
dP_len = asn1_get_int(buf, &offset, &dP);
|
dP_len = asn1_get_big_int(buf, &offset, &dP);
|
||||||
dQ_len = asn1_get_int(buf, &offset, &dQ);
|
dQ_len = asn1_get_big_int(buf, &offset, &dQ);
|
||||||
qInv_len = asn1_get_int(buf, &offset, &qInv);
|
qInv_len = asn1_get_big_int(buf, &offset, &qInv);
|
||||||
|
|
||||||
if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
|
if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)
|
||||||
return X509_INVALID_PRIV_KEY;
|
return X509_INVALID_PRIV_KEY;
|
||||||
@@ -295,25 +389,12 @@ static int asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version type of a certificate (which we don't actually care about)
|
* Get the version type of a certificate
|
||||||
*/
|
*/
|
||||||
int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
|
int asn1_version(const uint8_t *cert, int *offset, int *val)
|
||||||
{
|
{
|
||||||
int ret = X509_NOT_OK;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
(*offset) += 2; /* get past explicit tag */
|
(*offset) += 2; /* get past explicit tag */
|
||||||
if (cert[(*offset)++] != ASN1_INTEGER)
|
return asn1_get_int(cert, offset, val);
|
||||||
return X509_NOT_OK;
|
|
||||||
|
|
||||||
len = get_asn1_length(cert, offset);
|
|
||||||
if (len == 1)
|
|
||||||
{
|
|
||||||
ret = cert[*offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
*offset += len;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -463,8 +544,8 @@ int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)
|
|||||||
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
|
if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)
|
||||||
goto end_pub_key;
|
goto end_pub_key;
|
||||||
|
|
||||||
mod_len = asn1_get_int(cert, offset, &modulus);
|
mod_len = asn1_get_big_int(cert, offset, &modulus);
|
||||||
pub_len = asn1_get_int(cert, offset, &pub_exp);
|
pub_len = asn1_get_big_int(cert, offset, &pub_exp);
|
||||||
|
|
||||||
RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
|
RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);
|
||||||
|
|
||||||
@@ -584,7 +665,7 @@ int asn1_find_oid(const uint8_t* cert, int* offset,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int asn1_find_subjectaltname(const uint8_t* cert, int offset)
|
int asn1_is_subject_alt_name(const uint8_t *cert, int offset)
|
||||||
{
|
{
|
||||||
if (asn1_find_oid(cert, &offset, sig_subject_alt_name,
|
if (asn1_find_oid(cert, &offset, sig_subject_alt_name,
|
||||||
sizeof(sig_subject_alt_name)))
|
sizeof(sig_subject_alt_name)))
|
||||||
@@ -595,6 +676,39 @@ int asn1_find_subjectaltname(const uint8_t* cert, int offset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int asn1_is_basic_constraints(const uint8_t *cert, int offset)
|
||||||
|
{
|
||||||
|
if (asn1_find_oid(cert, &offset, sig_basic_constraints,
|
||||||
|
sizeof(sig_basic_constraints)))
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int asn1_is_key_usage(const uint8_t *cert, int offset)
|
||||||
|
{
|
||||||
|
if (asn1_find_oid(cert, &offset, sig_key_usage,
|
||||||
|
sizeof(sig_key_usage)))
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool asn1_is_critical_ext(const uint8_t *buf, int *offset)
|
||||||
|
{
|
||||||
|
/* critical is optional */
|
||||||
|
bool res = false;
|
||||||
|
|
||||||
|
if (asn1_next_obj(buf, offset, ASN1_BOOLEAN) == 1)
|
||||||
|
res = buf[(*offset)++] == 0xFF;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2007-2015, Cameron Rich
|
* Copyright (c) 2007-2016, Cameron Rich
|
||||||
*
|
*
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
@@ -56,6 +56,7 @@ extern "C" {
|
|||||||
#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
|
#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8
|
||||||
#define X509_INVALID_PRIV_KEY -9
|
#define X509_INVALID_PRIV_KEY -9
|
||||||
#define X509_MAX_CERTS -10
|
#define X509_MAX_CERTS -10
|
||||||
|
#define X509_VFY_ERROR_BASIC_CONSTRAINT -11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The Distinguished Name
|
* The Distinguished Name
|
||||||
@@ -68,6 +69,21 @@ extern "C" {
|
|||||||
#define X509_COUNTRY 4
|
#define X509_COUNTRY 4
|
||||||
#define X509_STATE 5
|
#define X509_STATE 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Key Usage bits
|
||||||
|
*/
|
||||||
|
#define IS_SET_KEY_USAGE_FLAG(A, B) (A->key_usage & B)
|
||||||
|
|
||||||
|
#define KEY_USAGE_DIGITAL_SIGNATURE 0x0001
|
||||||
|
#define KEY_USAGE_CONTENT_COMMITMENT 0x0002
|
||||||
|
#define KEY_USAGE_KEY_ENCIPHERMENT 0x0004
|
||||||
|
#define KEY_USAGE_DATA_ENCIPHERMENT 0x0008
|
||||||
|
#define KEY_USAGE_KEY_AGREEMENT 0x0010
|
||||||
|
#define KEY_USAGE_KEY_CERT_SIGN 0x0020
|
||||||
|
#define KEY_USAGE_CRL_SIGN 0x0040
|
||||||
|
#define KEY_USAGE_ENCIPHER_ONLY 0x0080
|
||||||
|
#define KEY_USAGE_DECIPHER_ONLY 0x0100
|
||||||
|
|
||||||
struct _x509_ctx
|
struct _x509_ctx
|
||||||
{
|
{
|
||||||
char *ca_cert_dn[X509_NUM_DN_TYPES];
|
char *ca_cert_dn[X509_NUM_DN_TYPES];
|
||||||
@@ -76,12 +92,19 @@ struct _x509_ctx
|
|||||||
time_t not_before;
|
time_t not_before;
|
||||||
time_t not_after;
|
time_t not_after;
|
||||||
uint8_t *signature;
|
uint8_t *signature;
|
||||||
uint16_t sig_len;
|
|
||||||
uint8_t sig_type;
|
|
||||||
RSA_CTX *rsa_ctx;
|
RSA_CTX *rsa_ctx;
|
||||||
bigint *digest;
|
bigint *digest;
|
||||||
uint8_t *fingerprint;
|
uint8_t *fingerprint;
|
||||||
uint8_t *spki_sha256;
|
uint8_t *spki_sha256;
|
||||||
|
uint16_t sig_len;
|
||||||
|
uint8_t sig_type;
|
||||||
|
bool basic_constraint_present;
|
||||||
|
bool basic_constraint_is_critical;
|
||||||
|
bool key_usage_present;
|
||||||
|
bool key_usage_is_critical;
|
||||||
|
bool basic_constaint_cA;
|
||||||
|
int basic_constraint_pathLenConstraint;
|
||||||
|
uint32_t key_usage;
|
||||||
struct _x509_ctx *next;
|
struct _x509_ctx *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -97,7 +120,8 @@ typedef struct
|
|||||||
int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
|
int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
|
||||||
void x509_free(X509_CTX *x509_ctx);
|
void x509_free(X509_CTX *x509_ctx);
|
||||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||||
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
|
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert,
|
||||||
|
int *pathLenConstraint);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SSL_FULL_MODE
|
#ifdef CONFIG_SSL_FULL_MODE
|
||||||
void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx);
|
void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx);
|
||||||
@@ -107,6 +131,7 @@ const char * x509_display_error(int error);
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* ASN1 declarations
|
* ASN1 declarations
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
#define ASN1_BOOLEAN 0x01
|
||||||
#define ASN1_INTEGER 0x02
|
#define ASN1_INTEGER 0x02
|
||||||
#define ASN1_BIT_STRING 0x03
|
#define ASN1_BIT_STRING 0x03
|
||||||
#define ASN1_OCTET_STRING 0x04
|
#define ASN1_OCTET_STRING 0x04
|
||||||
@@ -139,15 +164,21 @@ uint32_t get_asn1_length(const uint8_t *buf, int *offset);
|
|||||||
int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
|
int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
|
||||||
int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
|
int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
|
||||||
int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
|
int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
|
||||||
int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
|
int asn1_get_big_int(const uint8_t *buf, int *offset, uint8_t **object);
|
||||||
int asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
int asn1_get_int(const uint8_t *buf, int *offset, int32_t *val);
|
||||||
|
int asn1_get_bool(const uint8_t *buf, int *offset, bool *val);
|
||||||
|
int asn1_get_bit_string_as_int(const uint8_t *buf, int *offset, uint32_t *val);
|
||||||
|
int asn1_version(const uint8_t *cert, int *offset, int *val);
|
||||||
int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
int asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||||
int asn1_name(const uint8_t *cert, int *offset, char *dn[]);
|
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);
|
int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
||||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||||
int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);
|
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[]);
|
int asn1_compare_dn(char * const dn1[], char * const dn2[]);
|
||||||
|
int asn1_is_subject_alt_name(const uint8_t *cert, int offset);
|
||||||
|
int asn1_is_basic_constraints(const uint8_t *cert, int offset);
|
||||||
|
int asn1_is_key_usage(const uint8_t *cert, int offset);
|
||||||
|
bool asn1_is_critical_ext(const uint8_t *buf, int *offset);
|
||||||
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
#endif /* CONFIG_SSL_CERT_VERIFICATION */
|
||||||
int asn1_signature_type(const uint8_t *cert,
|
int asn1_signature_type(const uint8_t *cert,
|
||||||
int *offset, X509_CTX *x509_ctx);
|
int *offset, X509_CTX *x509_ctx);
|
||||||
|
@@ -105,7 +105,7 @@ int pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* unencrypted key? */
|
/* unencrypted key? */
|
||||||
if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)
|
if (asn1_get_big_int(buf, &offset, &version) > 0 && *version == 0)
|
||||||
{
|
{
|
||||||
ret = p8_add_key(ssl_ctx, buf);
|
ret = p8_add_key(ssl_ctx, buf);
|
||||||
goto error;
|
goto error;
|
||||||
@@ -257,7 +257,7 @@ int pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)
|
if (asn1_get_big_int(buf, &offset, &version) < 0 || *version != 3)
|
||||||
{
|
{
|
||||||
ret = SSL_ERROR_INVALID_VERSION;
|
ret = SSL_ERROR_INVALID_VERSION;
|
||||||
goto error;
|
goto error;
|
||||||
@@ -463,7 +463,7 @@ static int get_pbe_params(uint8_t *buf, int *offset,
|
|||||||
*salt = &buf[*offset];
|
*salt = &buf[*offset];
|
||||||
*offset += len;
|
*offset += len;
|
||||||
|
|
||||||
if ((len = asn1_get_int(buf, offset, &iter)) < 0)
|
if ((len = asn1_get_big_int(buf, offset, &iter)) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
*iterations = 0;
|
*iterations = 0;
|
||||||
|
@@ -2090,8 +2090,11 @@ error:
|
|||||||
EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
|
EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
int pathLenConstraint = 0;
|
||||||
|
|
||||||
SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
|
SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
|
||||||
ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
|
ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx,
|
||||||
|
&pathLenConstraint);
|
||||||
SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
|
SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
|
||||||
|
|
||||||
if (ret) /* modify into an SSL error type */
|
if (ret) /* modify into an SSL error type */
|
||||||
|
@@ -92,8 +92,10 @@ int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
|
|||||||
if (ret == SSL_OK) /* verify the cert */
|
if (ret == SSL_OK) /* verify the cert */
|
||||||
{
|
{
|
||||||
int cert_res;
|
int cert_res;
|
||||||
cert_res = x509_verify(
|
int pathLenConstraint = 0;
|
||||||
ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);
|
|
||||||
|
cert_res = x509_verify(ssl->ssl_ctx->ca_cert_ctx,
|
||||||
|
ssl->x509_ctx, &pathLenConstraint);
|
||||||
ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res);
|
ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
208
ssl/x509.c
208
ssl/x509.c
@@ -42,6 +42,13 @@
|
|||||||
#include "crypto_misc.h"
|
#include "crypto_misc.h"
|
||||||
|
|
||||||
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
#ifdef CONFIG_SSL_CERT_VERIFICATION
|
||||||
|
static int x509_v3_subject_alt_name(const uint8_t *cert, int offset,
|
||||||
|
X509_CTX *x509_ctx);
|
||||||
|
static int x509_v3_basic_constraints(const uint8_t *cert, int offset,
|
||||||
|
X509_CTX *x509_ctx);
|
||||||
|
static int x509_v3_key_usage(const uint8_t *cert, int offset,
|
||||||
|
X509_CTX *x509_ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the signature from a certificate.
|
* Retrieve the signature from a certificate.
|
||||||
*/
|
*/
|
||||||
@@ -95,11 +102,10 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
|
|||||||
if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
|
if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
|
||||||
goto end_cert;
|
goto end_cert;
|
||||||
|
|
||||||
if (cert[offset] == ASN1_EXPLICIT_TAG) /* optional version */
|
/* optional version */
|
||||||
{
|
if (cert[offset] == ASN1_EXPLICIT_TAG &&
|
||||||
if ((version = asn1_version(cert, &offset, x509_ctx)) == X509_NOT_OK)
|
asn1_version(cert, &offset, &version) == X509_NOT_OK)
|
||||||
goto end_cert;
|
goto end_cert;
|
||||||
}
|
|
||||||
|
|
||||||
if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
|
if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */
|
||||||
asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
|
asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)
|
||||||
@@ -197,50 +203,11 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version == 2 && cert[offset] == ASN1_V3_DATA)
|
if (version == 2 && asn1_next_obj(cert, &offset, ASN1_V3_DATA) > 0)
|
||||||
{
|
{
|
||||||
int suboffset;
|
x509_v3_subject_alt_name(cert, offset, x509_ctx);
|
||||||
|
x509_v3_basic_constraints(cert, offset, x509_ctx);
|
||||||
++offset;
|
x509_v3_key_usage(cert, offset, x509_ctx);
|
||||||
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 */
|
offset = end_tbs; /* skip the rest of v3 data */
|
||||||
@@ -268,6 +235,106 @@ end_cert:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */
|
||||||
|
static int x509_v3_subject_alt_name(const uint8_t *cert, int offset,
|
||||||
|
X509_CTX *x509_ctx)
|
||||||
|
{
|
||||||
|
if ((offset = asn1_is_subject_alt_name(cert, offset)) > 0)
|
||||||
|
{
|
||||||
|
/* ignore if present */
|
||||||
|
asn1_is_critical_ext(cert, &offset);
|
||||||
|
|
||||||
|
if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) > 0)
|
||||||
|
{
|
||||||
|
int altlen;
|
||||||
|
|
||||||
|
if ((altlen = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) > 0)
|
||||||
|
{
|
||||||
|
int endalt = offset + altlen;
|
||||||
|
int totalnames = 0;
|
||||||
|
|
||||||
|
while (offset < endalt)
|
||||||
|
{
|
||||||
|
int type = cert[offset++];
|
||||||
|
int dnslen = get_asn1_length(cert, &offset);
|
||||||
|
|
||||||
|
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 + offset, dnslen);
|
||||||
|
x509_ctx->subject_alt_dnsnames[
|
||||||
|
totalnames][dnslen] = 0;
|
||||||
|
++totalnames;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += dnslen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return X509_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic constraints - see https://tools.ietf.org/html/rfc5280#page-39
|
||||||
|
*/
|
||||||
|
static int x509_v3_basic_constraints(const uint8_t *cert, int offset,
|
||||||
|
X509_CTX *x509_ctx)
|
||||||
|
{
|
||||||
|
int ret = X509_OK;
|
||||||
|
|
||||||
|
if ((offset = asn1_is_basic_constraints(cert, offset)) == 0)
|
||||||
|
goto end_contraints;
|
||||||
|
|
||||||
|
x509_ctx->basic_constraint_present = true;
|
||||||
|
x509_ctx->basic_constraint_is_critical =
|
||||||
|
asn1_is_critical_ext(cert, &offset);
|
||||||
|
|
||||||
|
if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 ||
|
||||||
|
asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 ||
|
||||||
|
asn1_get_bool(cert, &offset, &x509_ctx->basic_constaint_cA) < 0 ||
|
||||||
|
asn1_get_int(cert, &offset,
|
||||||
|
&x509_ctx->basic_constraint_pathLenConstraint) < 0)
|
||||||
|
{
|
||||||
|
ret = X509_NOT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_contraints:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Key usage - see https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||||
|
*/
|
||||||
|
static int x509_v3_key_usage(const uint8_t *cert, int offset,
|
||||||
|
X509_CTX *x509_ctx)
|
||||||
|
{
|
||||||
|
int ret = X509_OK;
|
||||||
|
|
||||||
|
if ((offset = asn1_is_key_usage(cert, offset)) == 0)
|
||||||
|
goto end_key_usage;
|
||||||
|
|
||||||
|
x509_ctx->key_usage_present = true;
|
||||||
|
x509_ctx->key_usage_is_critical = asn1_is_critical_ext(cert, &offset);
|
||||||
|
|
||||||
|
if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 ||
|
||||||
|
asn1_get_bit_string_as_int(cert, &offset, &x509_ctx->key_usage))
|
||||||
|
{
|
||||||
|
ret = X509_NOT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_key_usage:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free an X.509 object's resources.
|
* Free an X.509 object's resources.
|
||||||
*/
|
*/
|
||||||
@@ -371,8 +438,10 @@ static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
|
|||||||
* - That the certificate(s) are not self-signed.
|
* - That the certificate(s) are not self-signed.
|
||||||
* - The certificate chain is valid.
|
* - The certificate chain is valid.
|
||||||
* - The signature of the certificate is valid.
|
* - The signature of the certificate is valid.
|
||||||
|
* - Basic constraints
|
||||||
*/
|
*/
|
||||||
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
|
int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert,
|
||||||
|
int *pathLenConstraint)
|
||||||
{
|
{
|
||||||
int ret = X509_OK, i = 0;
|
int ret = X509_OK, i = 0;
|
||||||
bigint *cert_sig;
|
bigint *cert_sig;
|
||||||
@@ -415,6 +484,13 @@ int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
|
|||||||
goto end_verify;
|
goto end_verify;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cert->basic_constaint_cA &&
|
||||||
|
IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN))
|
||||||
|
{
|
||||||
|
ret = X509_VFY_ERROR_BASIC_CONSTRAINT;
|
||||||
|
goto end_verify;
|
||||||
|
}
|
||||||
|
|
||||||
next_cert = cert->next;
|
next_cert = cert->next;
|
||||||
|
|
||||||
/* last cert in the chain - look for a trusted cert */
|
/* last cert in the chain - look for a trusted cert */
|
||||||
@@ -425,14 +501,29 @@ int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
|
|||||||
/* go thu the CA store */
|
/* go thu the CA store */
|
||||||
while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
|
while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])
|
||||||
{
|
{
|
||||||
|
/* ignore CA certs that are not really CA certs */
|
||||||
|
if (cert->basic_constraint_present &&
|
||||||
|
!ca_cert_ctx->cert[i]->basic_constaint_cA)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (asn1_compare_dn(cert->ca_cert_dn,
|
if (asn1_compare_dn(cert->ca_cert_dn,
|
||||||
ca_cert_ctx->cert[i]->cert_dn) == 0)
|
ca_cert_ctx->cert[i]->cert_dn) == 0)
|
||||||
{
|
{
|
||||||
/* use this CA certificate for signature verification */
|
/* use this CA certificate for signature verification */
|
||||||
match_ca_cert = 1;
|
match_ca_cert = true;
|
||||||
ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
|
ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;
|
||||||
mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
|
mod = ca_cert_ctx->cert[i]->rsa_ctx->m;
|
||||||
expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
|
expn = ca_cert_ctx->cert[i]->rsa_ctx->e;
|
||||||
|
|
||||||
|
if (ca_cert_ctx->cert[i]->basic_constaint_cA &&
|
||||||
|
ca_cert_ctx->cert[i]->
|
||||||
|
basic_constraint_pathLenConstraint <
|
||||||
|
*pathLenConstraint)
|
||||||
|
{
|
||||||
|
ret = X509_VFY_ERROR_BASIC_CONSTRAINT;
|
||||||
|
goto end_verify;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,7 +582,8 @@ int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert)
|
|||||||
/* go down the certificate chain using recursion. */
|
/* go down the certificate chain using recursion. */
|
||||||
if (next_cert != NULL)
|
if (next_cert != NULL)
|
||||||
{
|
{
|
||||||
ret = x509_verify(ca_cert_ctx, next_cert);
|
ret = x509_verify(ca_cert_ctx, next_cert, pathLenConstraint);
|
||||||
|
(*pathLenConstraint)++; /* don't include last certificate */
|
||||||
}
|
}
|
||||||
|
|
||||||
end_verify:
|
end_verify:
|
||||||
@@ -603,8 +695,19 @@ void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx)
|
|||||||
|
|
||||||
if (ca_cert_ctx)
|
if (ca_cert_ctx)
|
||||||
{
|
{
|
||||||
|
int pathLenConstraint = 0;
|
||||||
printf("Verify:\t\t\t\t%s\n",
|
printf("Verify:\t\t\t\t%s\n",
|
||||||
x509_display_error(x509_verify(ca_cert_ctx, cert)));
|
x509_display_error(x509_verify(ca_cert_ctx, cert,
|
||||||
|
&pathLenConstraint)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cert->basic_constraint_present)
|
||||||
|
{
|
||||||
|
printf("Basic Constraints:\t\t%s, CA:%s, pathlen:%d\n",
|
||||||
|
cert->basic_constraint_is_critical ?
|
||||||
|
"critical" : "NOT critical",
|
||||||
|
cert->basic_constaint_cA? "TRUE" : "FALSE",
|
||||||
|
cert->basic_constraint_pathLenConstraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -655,6 +758,9 @@ const char * x509_display_error(int error)
|
|||||||
case X509_INVALID_PRIV_KEY:
|
case X509_INVALID_PRIV_KEY:
|
||||||
return "Invalid private key";
|
return "Invalid private key";
|
||||||
|
|
||||||
|
case X509_VFY_ERROR_BASIC_CONSTRAINT:
|
||||||
|
return "Basic constraint invalid";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user