openssl: refactor certificate parsing to use OpenSSL memory BIO
Fixes #427
This commit is contained in:
parent
958d2ffb19
commit
c00cec9864
@ -1015,49 +1015,6 @@ void Curl_ossl_close_all(struct SessionHandle *data)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asn1_output(const ASN1_UTCTIME *tm,
|
|
||||||
char *buf,
|
|
||||||
size_t sizeofbuf)
|
|
||||||
{
|
|
||||||
const char *asn1_string;
|
|
||||||
int gmt=FALSE;
|
|
||||||
int i;
|
|
||||||
int year=0, month=0, day=0, hour=0, minute=0, second=0;
|
|
||||||
|
|
||||||
i=tm->length;
|
|
||||||
asn1_string=(const char *)tm->data;
|
|
||||||
|
|
||||||
if(i < 10)
|
|
||||||
return 1;
|
|
||||||
if(asn1_string[i-1] == 'Z')
|
|
||||||
gmt=TRUE;
|
|
||||||
for(i=0; i<10; i++)
|
|
||||||
if((asn1_string[i] > '9') || (asn1_string[i] < '0'))
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0');
|
|
||||||
if(year < 50)
|
|
||||||
year+=100;
|
|
||||||
|
|
||||||
month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0');
|
|
||||||
if((month > 12) || (month < 1))
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0');
|
|
||||||
hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0');
|
|
||||||
minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0');
|
|
||||||
|
|
||||||
if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
|
|
||||||
(asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
|
|
||||||
second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
|
|
||||||
|
|
||||||
snprintf(buf, sizeofbuf,
|
|
||||||
"%04d-%02d-%02d %02d:%02d:%02d %s",
|
|
||||||
year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====================================================== */
|
/* ====================================================== */
|
||||||
|
|
||||||
|
|
||||||
@ -2256,43 +2213,35 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define print_certinfo(_label, _num) \
|
||||||
|
do { \
|
||||||
|
long info_len = BIO_get_mem_data(mem, &ptr); \
|
||||||
|
infof(data, " %s: %.*s\n", _label, info_len, ptr); \
|
||||||
|
Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
|
||||||
|
BIO_reset(mem); \
|
||||||
|
} WHILE_FALSE
|
||||||
|
|
||||||
static void pubkey_show(struct SessionHandle *data,
|
static void pubkey_show(struct SessionHandle *data,
|
||||||
|
BIO *mem,
|
||||||
int num,
|
int num,
|
||||||
const char *type,
|
const char *type,
|
||||||
const char *name,
|
const char *name,
|
||||||
unsigned char *raw,
|
BIGNUM *bn)
|
||||||
int len)
|
|
||||||
{
|
{
|
||||||
size_t left;
|
char *ptr;
|
||||||
int i;
|
|
||||||
char namebuf[32];
|
char namebuf[32];
|
||||||
char *buffer;
|
|
||||||
|
|
||||||
left = len*3 + 1;
|
snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
|
||||||
buffer = malloc(left);
|
|
||||||
if(buffer) {
|
BN_print(mem, bn);
|
||||||
char *ptr=buffer;
|
|
||||||
snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
|
print_certinfo(namebuf, num);
|
||||||
for(i=0; i< len; i++) {
|
|
||||||
snprintf(ptr, left, "%02x:", raw[i]);
|
|
||||||
ptr += 3;
|
|
||||||
left -= 3;
|
|
||||||
}
|
|
||||||
infof(data, " %s: %s\n", namebuf, buffer);
|
|
||||||
Curl_ssl_push_certinfo(data, num, namebuf, buffer);
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define print_pubkey_BN(_type, _name, _num) \
|
#define print_pubkey_BN(_type, _name, _num) \
|
||||||
do { \
|
do { \
|
||||||
if(pubkey->pkey._type->_name) { \
|
if(pubkey->pkey._type->_name) { \
|
||||||
int len = BN_num_bytes(pubkey->pkey._type->_name); \
|
pubkey_show(data, mem, _num, #_type, #_name, pubkey->pkey._type->_name); \
|
||||||
if(len < CERTBUFFERSIZE) { \
|
|
||||||
BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)bufp); \
|
|
||||||
bufp[len] = 0; \
|
|
||||||
pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \
|
|
||||||
} \
|
|
||||||
} \
|
} \
|
||||||
} WHILE_FALSE
|
} WHILE_FALSE
|
||||||
|
|
||||||
@ -2334,7 +2283,7 @@ static int X509V3_ext(struct SessionHandle *data,
|
|||||||
/* biomem->length bytes at biomem->data, this little loop here is only
|
/* biomem->length bytes at biomem->data, this little loop here is only
|
||||||
done for the infof() call, we send the "raw" data to the certinfo
|
done for the infof() call, we send the "raw" data to the certinfo
|
||||||
function */
|
function */
|
||||||
for(j=0; j<(size_t)biomem->length; j++) {
|
for(j = 0; j < (size_t)biomem->length; j++) {
|
||||||
const char *sep="";
|
const char *sep="";
|
||||||
if(biomem->data[j] == '\n') {
|
if(biomem->data[j] == '\n') {
|
||||||
sep=", ";
|
sep=", ";
|
||||||
@ -2356,46 +2305,6 @@ static int X509V3_ext(struct SessionHandle *data,
|
|||||||
return 0; /* all is fine */
|
return 0; /* all is fine */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void X509_signature(struct SessionHandle *data,
|
|
||||||
int numcert,
|
|
||||||
ASN1_STRING *sig)
|
|
||||||
{
|
|
||||||
char buf[1024];
|
|
||||||
char *ptr = buf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i=0; i<sig->length; i++)
|
|
||||||
ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
|
|
||||||
|
|
||||||
infof(data, " Signature: %s\n", buf);
|
|
||||||
Curl_ssl_push_certinfo(data, numcert, "Signature", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
|
|
||||||
{
|
|
||||||
BIO *bio_out = BIO_new(BIO_s_mem());
|
|
||||||
BUF_MEM *biomem;
|
|
||||||
|
|
||||||
/* this outputs the cert in this 64 column wide style with newlines and
|
|
||||||
-----BEGIN CERTIFICATE----- texts and more */
|
|
||||||
PEM_write_bio_X509(bio_out, x);
|
|
||||||
|
|
||||||
BIO_get_mem_ptr(bio_out, &biomem);
|
|
||||||
|
|
||||||
Curl_ssl_push_certinfo_len(data, numcert,
|
|
||||||
"Cert", biomem->data, biomem->length);
|
|
||||||
|
|
||||||
BIO_free(bio_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This size was previously 512 which has been reported "too small" without
|
|
||||||
* any specifics, so it was enlarged to allow more data to get shown uncut.
|
|
||||||
* The "perfect" size is yet to figure out.
|
|
||||||
*/
|
|
||||||
#define CERTBUFFERSIZE 8192
|
|
||||||
|
|
||||||
static CURLcode get_cert_chain(struct connectdata *conn,
|
static CURLcode get_cert_chain(struct connectdata *conn,
|
||||||
struct ssl_connect_data *connssl)
|
struct ssl_connect_data *connssl)
|
||||||
|
|
||||||
@ -2403,17 +2312,12 @@ static CURLcode get_cert_chain(struct connectdata *conn,
|
|||||||
CURLcode result;
|
CURLcode result;
|
||||||
STACK_OF(X509) *sk;
|
STACK_OF(X509) *sk;
|
||||||
int i;
|
int i;
|
||||||
char *bufp;
|
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
int numcerts;
|
int numcerts;
|
||||||
|
BIO *mem;
|
||||||
bufp = malloc(CERTBUFFERSIZE);
|
|
||||||
if(!bufp)
|
|
||||||
return CURLE_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
sk = SSL_get_peer_cert_chain(connssl->handle);
|
sk = SSL_get_peer_cert_chain(connssl->handle);
|
||||||
if(!sk) {
|
if(!sk) {
|
||||||
free(bufp);
|
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2421,87 +2325,59 @@ static CURLcode get_cert_chain(struct connectdata *conn,
|
|||||||
|
|
||||||
result = Curl_ssl_init_certinfo(data, numcerts);
|
result = Curl_ssl_init_certinfo(data, numcerts);
|
||||||
if(result) {
|
if(result) {
|
||||||
free(bufp);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
infof(data, "--- Certificate chain\n");
|
mem = BIO_new(BIO_s_mem());
|
||||||
for(i=0; i<numcerts; i++) {
|
|
||||||
long value;
|
infof(data, "--- Certificate chain\n");
|
||||||
ASN1_INTEGER *num;
|
for(i = 0; i < numcerts; i++) {
|
||||||
ASN1_TIME *certdate;
|
long value, len;
|
||||||
|
ASN1_INTEGER *num;
|
||||||
|
|
||||||
/* get the certs in "importance order" */
|
|
||||||
#if 0
|
|
||||||
X509 *x = sk_X509_value(sk, numcerts - i - 1);
|
|
||||||
#else
|
|
||||||
X509 *x = sk_X509_value(sk, i);
|
X509 *x = sk_X509_value(sk, i);
|
||||||
#endif
|
|
||||||
|
|
||||||
X509_CINF *cinf;
|
X509_CINF *cinf;
|
||||||
EVP_PKEY *pubkey=NULL;
|
EVP_PKEY *pubkey=NULL;
|
||||||
int j;
|
int j;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
(void)x509_name_oneline(X509_get_subject_name(x), bufp, CERTBUFFERSIZE);
|
X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
|
||||||
infof(data, "%2d Subject: %s\n", i, bufp);
|
len = BIO_get_mem_data(mem, &ptr);
|
||||||
Curl_ssl_push_certinfo(data, i, "Subject", bufp);
|
infof(data, "%2d Subject: %.*s\n", len, i, ptr);
|
||||||
|
Curl_ssl_push_certinfo_len(data, i, "Subject", ptr, len);
|
||||||
|
BIO_reset(mem);
|
||||||
|
|
||||||
(void)x509_name_oneline(X509_get_issuer_name(x), bufp, CERTBUFFERSIZE);
|
X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
|
||||||
infof(data, " Issuer: %s\n", bufp);
|
print_certinfo("Issuer", i);
|
||||||
Curl_ssl_push_certinfo(data, i, "Issuer", bufp);
|
|
||||||
|
|
||||||
value = X509_get_version(x);
|
value = X509_get_version(x);
|
||||||
|
BIO_printf(mem, "%lx", value);
|
||||||
|
len = BIO_get_mem_data(mem, &ptr);
|
||||||
infof(data, " Version: %lu (0x%lx)\n", value+1, value);
|
infof(data, " Version: %lu (0x%lx)\n", value+1, value);
|
||||||
snprintf(bufp, CERTBUFFERSIZE, "%lx", value);
|
Curl_ssl_push_certinfo_len(data, i, "Version", ptr, len); /* hex */
|
||||||
Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */
|
BIO_reset(mem);
|
||||||
|
|
||||||
num=X509_get_serialNumber(x);
|
num = X509_get_serialNumber(x);
|
||||||
{
|
if(num->type == V_ASN1_NEG_INTEGER)
|
||||||
int left = CERTBUFFERSIZE;
|
BIO_puts(mem, "-");
|
||||||
|
for(j = 0; j < num->length; j++)
|
||||||
ptr = bufp;
|
BIO_printf(mem, "%02x", num->data[j]);
|
||||||
if(num->type == V_ASN1_NEG_INTEGER) {
|
print_certinfo("Serial Number", i);
|
||||||
*ptr++='-';
|
|
||||||
left--;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(j=0; (j<num->length) && (left>=3); j++) {
|
|
||||||
snprintf(ptr, left, "%02x", num->data[j]);
|
|
||||||
ptr += 2;
|
|
||||||
left -= 2;
|
|
||||||
}
|
|
||||||
if(num->length)
|
|
||||||
infof(data, " Serial Number: %s\n", bufp);
|
|
||||||
else
|
|
||||||
bufp[0]=0;
|
|
||||||
}
|
|
||||||
if(bufp[0])
|
|
||||||
Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */
|
|
||||||
|
|
||||||
cinf = x->cert_info;
|
cinf = x->cert_info;
|
||||||
|
|
||||||
j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE);
|
i2a_ASN1_OBJECT(mem, cinf->signature->algorithm);
|
||||||
if(!j) {
|
print_certinfo("Signature Algorithm", i);
|
||||||
infof(data, " Signature Algorithm: %s\n", bufp);
|
|
||||||
Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp);
|
|
||||||
}
|
|
||||||
|
|
||||||
certdate = X509_get_notBefore(x);
|
ASN1_TIME_print(mem, X509_get_notBefore(x));
|
||||||
asn1_output(certdate, bufp, CERTBUFFERSIZE);
|
print_certinfo("Start date", i);
|
||||||
infof(data, " Start date: %s\n", bufp);
|
|
||||||
Curl_ssl_push_certinfo(data, i, "Start date", bufp);
|
|
||||||
|
|
||||||
certdate = X509_get_notAfter(x);
|
ASN1_TIME_print(mem, X509_get_notAfter(x));
|
||||||
asn1_output(certdate, bufp, CERTBUFFERSIZE);
|
print_certinfo("Expire date", i);
|
||||||
infof(data, " Expire date: %s\n", bufp);
|
|
||||||
Curl_ssl_push_certinfo(data, i, "Expire date", bufp);
|
|
||||||
|
|
||||||
j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE);
|
i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm);
|
||||||
if(!j) {
|
print_certinfo("Public Key Algorithm", i);
|
||||||
infof(data, " Public Key Algorithm: %s\n", bufp);
|
|
||||||
Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp);
|
|
||||||
}
|
|
||||||
|
|
||||||
pubkey = X509_get_pubkey(x);
|
pubkey = X509_get_pubkey(x);
|
||||||
if(!pubkey)
|
if(!pubkey)
|
||||||
@ -2511,8 +2387,10 @@ static CURLcode get_cert_chain(struct connectdata *conn,
|
|||||||
case EVP_PKEY_RSA:
|
case EVP_PKEY_RSA:
|
||||||
infof(data, " RSA Public Key (%d bits)\n",
|
infof(data, " RSA Public Key (%d bits)\n",
|
||||||
BN_num_bits(pubkey->pkey.rsa->n));
|
BN_num_bits(pubkey->pkey.rsa->n));
|
||||||
snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n));
|
BIO_printf(mem, "%d", BN_num_bits(pubkey->pkey.rsa->n));
|
||||||
Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp);
|
len = BIO_get_mem_data(mem, &ptr);
|
||||||
|
Curl_ssl_push_certinfo_len(data, i, "RSA Public Key", ptr, len);
|
||||||
|
BIO_reset(mem);
|
||||||
|
|
||||||
print_pubkey_BN(rsa, n, i);
|
print_pubkey_BN(rsa, n, i);
|
||||||
print_pubkey_BN(rsa, e, i);
|
print_pubkey_BN(rsa, e, i);
|
||||||
@ -2547,12 +2425,20 @@ static CURLcode get_cert_chain(struct connectdata *conn,
|
|||||||
|
|
||||||
X509V3_ext(data, i, cinf->extensions);
|
X509V3_ext(data, i, cinf->extensions);
|
||||||
|
|
||||||
X509_signature(data, i, x->signature);
|
for(j = 0; j < x->signature->length; j++)
|
||||||
|
BIO_printf(mem, "%02x:", x->signature->data[j]);
|
||||||
|
len = BIO_get_mem_data(mem, &ptr);
|
||||||
|
infof(data, " Signature: %.*s", len, ptr);
|
||||||
|
Curl_ssl_push_certinfo_len(data, i, "Signature", ptr, len);
|
||||||
|
BIO_reset(mem);
|
||||||
|
|
||||||
dumpcert(data, x, i);
|
PEM_write_bio_X509(mem, x);
|
||||||
|
len = BIO_get_mem_data(mem, &ptr);
|
||||||
|
Curl_ssl_push_certinfo_len(data, i, "Cert", ptr, len);
|
||||||
|
BIO_reset(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(bufp);
|
BIO_free(mem);
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
@ -2630,13 +2516,13 @@ static CURLcode servercert(struct connectdata *conn,
|
|||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
int rc;
|
int rc;
|
||||||
long lerr;
|
long lerr, len;
|
||||||
ASN1_TIME *certdate;
|
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
X509 *issuer;
|
X509 *issuer;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
char *buffer = data->state.buffer;
|
char *buffer = data->state.buffer;
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
|
BIO *mem = BIO_new(BIO_s_mem());
|
||||||
|
|
||||||
if(data->set.ssl.certinfo)
|
if(data->set.ssl.certinfo)
|
||||||
/* we've been asked to gather certificate info! */
|
/* we've been asked to gather certificate info! */
|
||||||
@ -2657,13 +2543,17 @@ static CURLcode servercert(struct connectdata *conn,
|
|||||||
buffer, BUFSIZE);
|
buffer, BUFSIZE);
|
||||||
infof(data, "\t subject: %s\n", rc?"[NONE]":buffer);
|
infof(data, "\t subject: %s\n", rc?"[NONE]":buffer);
|
||||||
|
|
||||||
certdate = X509_get_notBefore(connssl->server_cert);
|
ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert));
|
||||||
asn1_output(certdate, buffer, BUFSIZE);
|
len = BIO_get_mem_data(mem, &ptr);
|
||||||
infof(data, "\t start date: %s\n", buffer);
|
infof(data, "\t start date: %.*s\n", len, ptr);
|
||||||
|
BIO_reset(mem);
|
||||||
|
|
||||||
certdate = X509_get_notAfter(connssl->server_cert);
|
ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert));
|
||||||
asn1_output(certdate, buffer, BUFSIZE);
|
len = BIO_get_mem_data(mem, &ptr);
|
||||||
infof(data, "\t expire date: %s\n", buffer);
|
infof(data, "\t expire date: %.*s\n", len, ptr);
|
||||||
|
BIO_reset(mem);
|
||||||
|
|
||||||
|
BIO_free(mem);
|
||||||
|
|
||||||
if(data->set.ssl.verifyhost) {
|
if(data->set.ssl.verifyhost) {
|
||||||
result = verifyhost(conn, connssl->server_cert);
|
result = verifyhost(conn, connssl->server_cert);
|
||||||
|
Loading…
Reference in New Issue
Block a user