New ctrls to retrieve supported signature algorithms and curves and
authorDr. Stephen Henson <steve@openssl.org>
Tue, 6 Mar 2012 14:28:21 +0000 (14:28 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 6 Mar 2012 14:28:21 +0000 (14:28 +0000)
extensions to s_client and s_server to print out retrieved valued.

Extend CERT structure to cache supported signature algorithm data.

CHANGES
apps/s_apps.h
apps/s_cb.c
apps/s_client.c
apps/s_server.c
ssl/s3_lib.c
ssl/ssl.h
ssl/ssl_cert.c
ssl/ssl_locl.h
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index 5dbdfc50067d7253a9c47b87e2d2e48a91817c58..dc7636e4d4277cda6abc1e8acd73abe06a30eff4 100644 (file)
--- 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.
index 820e5c58155b440c4cf1bd8972ae27027785a905..39a11d9a775a8b9bb7933e596508690cda251fdf 100644 (file)
@@ -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);
index 38eae7fe367725b314eb2196d4fa6deb73d1c998..7eaffa8a5afc4c53b76b36db7b9de3a413f4387b 100644 (file)
@@ -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)
        {
index 7f389712dcc78bb9d6a4b05ded8b4d0daf56dfd3..ce199be81bbb57e5dc50bdbbd0dcfc454770f42d 100644 (file)
@@ -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)));
index 1f4b85bb5970bb9200e3b43269e8d7ef3c4212ee..4603cdafcd12a9c7dd9c59c6718713ed77ad279b 100644 (file)
@@ -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, "));
index db79a99ccd69cfaa66f5fa0f974a76650b688480..248bb94df843f63748113c82571c362e9b5a199a 100644 (file)
@@ -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;
                }
index 8998e9ad652c06cc9e5a61efa5a06d464798c123..3e255fcfeed1e347cd44a68569679cb45b806f23 100644 (file)
--- 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);
index c48aa20923b647cec39756b0e7a8c4143cbdc99f..6a1c484fc3c5def0f053311b417edb8e67077e16 100644 (file)
@@ -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);
        }
 
index bdaca8bf4004e0085e93e0f9f7fa596ca30c143b..ad5dc7104937299fee9678faff006b8e863356c4 100644 (file)
@@ -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    */
 
index 9c76da1120a9a67cbc18df988f47d1dcdb08fc65..dfd397f9b7d033a2df650f4a0ff20def7cb7a8ea 100644 (file)
@@ -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)
index c5e3a70022b5ac5c13b1176db53ad6757af1bcb0..cca04b8742ccf76935675799bba1820a23ee6212 100644 (file)
@@ -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)