diff --git a/CHANGES b/CHANGES index 5dbdfc5006..dc7636e4d4 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,11 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) New ctrls to retrieve supported signature algorithms and + supported curve values as an array of NIDs. Extend openssl utility + to print out received values. + [Steve Henson] + *) Add new APIs EC_curve_nist2nid and EC_curve_nid2nist which convert between NIDs and the more common NIST names such as "P-256". Enhance ecparam utility and ECC method to recognise the NIST names for curves. diff --git a/apps/s_apps.h b/apps/s_apps.h index 820e5c5815..39a11d9a77 100644 --- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -155,6 +155,8 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx); #ifdef HEADER_SSL_H int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file); int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key); +int ssl_print_sigalgs(BIO *out, SSL *s); +int ssl_print_curves(BIO *out, SSL *s); #endif int init_client(int *sock, char *server, int port, int type); int should_retry(int i); diff --git a/apps/s_cb.c b/apps/s_cb.c index 38eae7fe36..7eaffa8a5a 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -278,6 +278,77 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key) return 1; } +int ssl_print_sigalgs(BIO *out, SSL *s) + { + int i, nsig; + nsig = SSL_get_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL); + if (nsig == 0) + return 1; + + BIO_puts(out, "Signature Algorithms: "); + for (i = 0; i < nsig; i++) + { + int hash_nid, sign_nid; + unsigned char rhash, rsign; + const char *sstr = NULL; + SSL_get_sigalgs(s, i, &sign_nid, &hash_nid, NULL, + &rsign, &rhash); + if (i) + BIO_puts(out, ":"); + if (sign_nid == EVP_PKEY_RSA) + sstr = "RSA"; + else if(sign_nid == EVP_PKEY_DSA) + sstr = "DSA"; + else if(sign_nid == EVP_PKEY_EC) + sstr = "ECDSA"; + if (sstr) + BIO_printf(out,"%s+", sstr); + else + BIO_printf(out,"0x%02X+", (int)rsign); + if (hash_nid != NID_undef) + BIO_printf(out, "%s", OBJ_nid2sn(hash_nid)); + else + BIO_printf(out,"0x%02X", (int)rhash); + } + BIO_puts(out, "\n"); + return 1; + } + +int ssl_print_curves(BIO *out, SSL *s) + { + int i, ncurves, *curves; + ncurves = SSL_get1_curvelist(s, NULL); + if (ncurves <= 0) + return 1; + curves = OPENSSL_malloc(ncurves * sizeof(int)); + SSL_get1_curvelist(s, curves); + + BIO_puts(out, "Supported Elliptic Curves: "); + for (i = 0; i < ncurves; i++) + { + int nid; + const char *cname; + if (i) + BIO_puts(out, ":"); + nid = curves[i]; + /* If unrecognised print out hex version */ + if (nid & TLSEXT_nid_unknown) + BIO_printf(out, "0x%04X", nid & 0xFFFF); + else + { + /* Use NIST name for curve if it exists */ + cname = EC_curve_nid2nist(nid); + if (!cname) + cname = OBJ_nid2sn(nid); + BIO_printf(out, "%s", cname); + } + } + BIO_puts(out, "\n"); + OPENSSL_free(curves); + return 1; + } + + long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp, int argi, long argl, long ret) { diff --git a/apps/s_client.c b/apps/s_client.c index 7f389712dc..ce199be81b 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -2018,6 +2018,8 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_write(bio,"\n",1); } + ssl_print_sigalgs(bio, s); + BIO_printf(bio,"---\nSSL handshake has read %ld bytes and written %ld bytes\n", BIO_number_read(SSL_get_rbio(s)), BIO_number_written(SSL_get_wbio(s))); diff --git a/apps/s_server.c b/apps/s_server.c index 1f4b85bb59..4603cdafcd 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -2472,7 +2472,10 @@ static int init_ssl_connection(SSL *con) if (SSL_get_shared_ciphers(con,buf,sizeof buf) != NULL) BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf); str=SSL_CIPHER_get_name(SSL_get_current_cipher(con)); + ssl_print_sigalgs(bio_s_out, con); + ssl_print_curves(bio_s_out, con); BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)"); + #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len); if (next_proto_neg) @@ -2806,6 +2809,8 @@ static int www_body(char *hostname, int s, unsigned char *context) } BIO_puts(io,"\n"); } + ssl_print_sigalgs(io, con); + ssl_print_curves(io, con); BIO_printf(io,(SSL_cache_hit(con) ?"---\nReused, " :"---\nNew, ")); diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index db79a99ccd..248bb94df8 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3365,6 +3365,32 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) else return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg); + case SSL_CTRL_GET_CURVELIST: + { + unsigned char *clist; + size_t clistlen; + if (!s->session) + return 0; + clist = s->session->tlsext_ellipticcurvelist; + clistlen = s->session->tlsext_ellipticcurvelist_length / 2; + if (parg) + { + size_t i; + int *cptr = parg; + unsigned int cid, nid; + for (i = 0; i < clistlen; i++) + { + n2s(clist, cid); + nid = tls1_ec_curve_id2nid(cid); + if (nid != 0) + cptr[i] = nid; + else + cptr[i] = TLSEXT_nid_unknown | cid; + } + } + return (int)clistlen; + } + default: break; } diff --git a/ssl/ssl.h b/ssl/ssl.h index 8998e9ad65..3e255fcfee 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -366,6 +366,7 @@ typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; typedef struct ssl_method_st SSL_METHOD; typedef struct ssl_cipher_st SSL_CIPHER; typedef struct ssl_session_st SSL_SESSION; +typedef struct tls_sigalgs_st TLS_SIGALGS; DECLARE_STACK_OF(SSL_CIPHER) @@ -1617,6 +1618,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_CHAIN 88 #define SSL_CTRL_CHAIN_CERT 89 +#define SSL_CTRL_GET_CURVELIST 90 + #define DTLSv1_get_timeout(ssl, arg) \ SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg) #define DTLSv1_handle_timeout(ssl) \ @@ -1675,6 +1678,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,0,(char *)x509) #define SSL_add1_chain_cert(ctx,x509) \ SSL_ctrl(ctx,SSL_CTRL_CHAIN_CERT,1,(char *)x509) +#define SSL_get1_curvelist(ctx, s) \ + SSL_ctrl(ctx,SSL_CTRL_GET_CURVELIST,0,(char *)s) + #ifndef OPENSSL_NO_BIO BIO_METHOD *BIO_f_ssl(void); diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index c48aa20923..6a1c484fc3 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -339,6 +339,9 @@ CERT *ssl_cert_dup(CERT *cert) * will be set during handshake. */ ssl_cert_set_default_md(ret); + /* Sigalgs set to NULL as we get these from handshake too */ + ret->sigalgs = NULL; + ret->sigalgslen = 0; return(ret); @@ -418,6 +421,8 @@ void ssl_cert_free(CERT *c) EVP_PKEY_free(c->pkeys[i].publickey); #endif } + if (c->sigalgs) + OPENSSL_free(c->sigalgs); OPENSSL_free(c); } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index bdaca8bf40..ad5dc71049 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -506,6 +506,11 @@ typedef struct cert_st CERT_PKEY pkeys[SSL_PKEY_NUM]; + /* Array of pairs of NIDs for signature algorithm extension */ + TLS_SIGALGS *sigalgs; + /* Size of above array */ + size_t sigalgslen; + int references; /* >1 only if SSL_copy_session_id is used */ } CERT; @@ -534,7 +539,19 @@ typedef struct sess_cert_st int references; /* actually always 1 at the moment */ } SESS_CERT; - +/* Structure containing decoded values of signature algorithms extension */ +struct tls_sigalgs_st + { + /* NID of hash algorithm */ + int hash_nid; + /* NID of signature algorithm */ + int sign_nid; + /* Combined hash and signature NID */ + int signandhash_nid; + /* Raw values used in extension */ + unsigned char rsign; + unsigned char rhash; + }; /*#define MAC_DEBUG */ diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 9c76da1120..dfd397f9b7 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -2241,32 +2241,18 @@ typedef struct } tls12_lookup; static tls12_lookup tls12_md[] = { -#ifndef OPENSSL_NO_MD5 {NID_md5, TLSEXT_hash_md5}, -#endif -#ifndef OPENSSL_NO_SHA {NID_sha1, TLSEXT_hash_sha1}, -#endif -#ifndef OPENSSL_NO_SHA256 {NID_sha224, TLSEXT_hash_sha224}, {NID_sha256, TLSEXT_hash_sha256}, -#endif -#ifndef OPENSSL_NO_SHA512 {NID_sha384, TLSEXT_hash_sha384}, {NID_sha512, TLSEXT_hash_sha512} -#endif }; static tls12_lookup tls12_sig[] = { -#ifndef OPENSSL_NO_RSA {EVP_PKEY_RSA, TLSEXT_signature_rsa}, -#endif -#ifndef OPENSSL_NO_RSA {EVP_PKEY_DSA, TLSEXT_signature_dsa}, -#endif -#ifndef OPENSSL_NO_ECDSA {EVP_PKEY_EC, TLSEXT_signature_ecdsa} -#endif }; static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen) @@ -2279,18 +2265,17 @@ static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen) } return -1; } -#if 0 + static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen) { size_t i; for (i = 0; i < tlen; i++) { - if (table[i].id == id) + if ((table[i].id) == id) return table[i].nid; } - return -1; + return NID_undef; } -#endif int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md) { @@ -2358,6 +2343,7 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) int i, idx; const EVP_MD *md; CERT *c = s->cert; + TLS_SIGALGS *sigptr; /* Extension ignored for TLS versions below 1.2 */ if (TLS1_get_version(s) < TLS1_2_VERSION) return 1; @@ -2370,11 +2356,26 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL; c->pkeys[SSL_PKEY_ECC].digest = NULL; - for (i = 0; i < dsize; i += 2) - { - unsigned char hash_alg = data[i], sig_alg = data[i+1]; + if (c->sigalgs) + OPENSSL_free(c->sigalgs); + c->sigalgs = OPENSSL_malloc((dsize/2) * sizeof(TLS_SIGALGS)); + if (!c->sigalgs) + return 0; + c->sigalgslen = dsize/2; - switch(sig_alg) + for (i = 0, sigptr = c->sigalgs; i < dsize; i += 2, sigptr++) + { + sigptr->rhash = data[i]; + sigptr->rsign = data[i + 1]; + sigptr->hash_nid = tls12_find_nid(sigptr->rhash, tls12_md, + sizeof(tls12_md)/sizeof(tls12_lookup)); + sigptr->sign_nid = tls12_find_nid(sigptr->rsign, tls12_sig, + sizeof(tls12_sig)/sizeof(tls12_lookup)); + if (!OBJ_find_sigid_by_algs(&sigptr->signandhash_nid, + sigptr->hash_nid, + sigptr->sign_nid)) + sigptr->signandhash_nid = NID_undef; + switch(sigptr->rsign) { #ifndef OPENSSL_NO_RSA case TLSEXT_signature_rsa: @@ -2397,7 +2398,7 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) if (c->pkeys[idx].digest == NULL) { - md = tls12_get_hash(hash_alg); + md = tls12_get_hash(sigptr->rhash); if (md) { c->pkeys[idx].digest = md; @@ -2432,6 +2433,33 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) #endif +int SSL_get_sigalgs(SSL *s, int idx, + int *psign, int *phash, int *psignandhash, + unsigned char *rsig, unsigned char *rhash) + { + if (s->cert->sigalgs == NULL) + return 0; + if (idx >= 0) + { + TLS_SIGALGS *psig; + if (idx >= (int)s->cert->sigalgslen) + return 0; + psig = s->cert->sigalgs + idx; + if (psign) + *psign = psig->sign_nid; + if (phash) + *phash = psig->hash_nid; + if (psignandhash) + *psignandhash = psig->signandhash_nid; + if (rsig) + *rsig = psig->rsign; + if (rhash) + *rhash = psig->rhash; + } + return s->cert->sigalgslen; + } + + #ifndef OPENSSL_NO_HEARTBEATS int tls1_process_heartbeat(SSL *s) diff --git a/ssl/tls1.h b/ssl/tls1.h index c5e3a70022..cca04b8742 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -252,6 +252,8 @@ extern "C" { #define TLSEXT_hash_sha256 4 #define TLSEXT_hash_sha384 5 #define TLSEXT_hash_sha512 6 +/* Flag set for unrecognised algorithms */ +#define TLSEXT_nid_unknown 0x1000000 /* ExtensionType value from RFC5764 */ #define TLSEXT_TYPE_use_srtp 14 @@ -276,6 +278,10 @@ int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen, const char *label, size_t llen, const unsigned char *p, size_t plen, int use_context); +int SSL_get_sigalgs(SSL *s, int idx, + int *psign, int *phash, int *psignandhash, + unsigned char *rsig, unsigned char *rhash); + #define SSL_set_tlsext_host_name(s,name) \ SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)