Add support for custom signature parameters
authorDr. Stephen Henson <steve@openssl.org>
Fri, 21 Apr 2017 14:56:34 +0000 (15:56 +0100)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 25 Apr 2017 21:12:34 +0000 (22:12 +0100)
Many signature types define the digest and public key type by a single OID
such as ecdsa_with_sha256.

Some types (RSA-PSS for example) use a single OID to indicate the signature
scheme and additional parameters are encoded in the AlgorithmIdentifier.

Add an X509_SIG_INFO structure to contain details about the signature type:
specifically the digest algorithm, public key algorithm, security bits and
various flags. This supports both existing algorithms and more complex
types.

Add accessors for the structure and a special case that retrieves signature
information from a certificate.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3301)

crypto/include/internal/asn1_int.h
crypto/include/internal/x509_int.h
crypto/x509/x509_lcl.h
crypto/x509/x509_set.c
crypto/x509v3/v3_purp.c
include/openssl/ossl_typ.h
include/openssl/x509.h

index f78ced6dabffd7722c7b2ac65d99f358735f6d41..6e6e0287381e7e7f48317821c026d25dc9c115ec 100644 (file)
@@ -52,6 +52,8 @@ struct evp_pkey_asn1_method_st {
     int (*item_sign) (EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
                       X509_ALGOR *alg1, X509_ALGOR *alg2,
                       ASN1_BIT_STRING *sig);
+    int (*siginf_set) (X509_SIG_INFO *siginf, const X509_ALGOR *alg,
+                       const ASN1_STRING *sig);
 } /* EVP_PKEY_ASN1_METHOD */ ;
 
 DEFINE_STACK_OF_CONST(EVP_PKEY_ASN1_METHOD)
index 10b605f709694ca43a5e3831bc03c6d888e58773..124cc533bc562c6258cf842513d876dbcb7b7e8a 100644 (file)
@@ -37,6 +37,19 @@ struct X509_name_st {
     int canon_enclen;
 } /* X509_NAME */ ;
 
+/* Signature info structure */
+
+struct x509_sig_info_st {
+    /* NID of message digest */
+    int mdnid;
+    /* NID of public key algorithm */
+    int pknid;
+    /* Security bits */
+    int secbits;
+    /* Various flags */
+    uint32_t flags;
+};
+
 /* PKCS#10 certificate request */
 
 struct X509_req_info_st {
@@ -146,6 +159,7 @@ struct x509_st {
     X509_CINF cert_info;
     X509_ALGOR sig_alg;
     ASN1_BIT_STRING signature;
+    X509_SIG_INFO siginf;
     CRYPTO_REF_COUNT references;
     CRYPTO_EX_DATA ex_data;
     /* These contain copies of various extension values */
@@ -267,3 +281,5 @@ struct x509_object_st {
 
 int a2i_ipadd(unsigned char *ipout, const char *ipasc);
 int x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm);
+
+void x509_init_sig_info(X509 *x);
index 34e413530a2c8445cf29852abe8f64dedd35c09e..401f2e9f55495cddd09113496a3593e72ce9421b 100644 (file)
@@ -142,3 +142,6 @@ DEFINE_STACK_OF(BY_DIR_HASH)
 DEFINE_STACK_OF(BY_DIR_ENTRY)
 typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY;
 DEFINE_STACK_OF(STACK_OF_X509_NAME_ENTRY)
+
+void x509_set_signature_info(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
+                             const ASN1_STRING *sig);
index e46174a463c4244645a1f03bcc3e813aed5097a1..08b71ff58212968203bd49d318394a09a9e04464 100644 (file)
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include "internal/asn1_int.h"
 #include "internal/x509_int.h"
+#include "x509_lcl.h"
 
 int X509_set_version(X509 *x, long version)
 {
@@ -157,3 +160,77 @@ const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x)
 {
     return &x->cert_info.signature;
 }
+
+int X509_SIG_INFO_get(const X509_SIG_INFO *siginf, int *mdnid, int *pknid,
+                      int *secbits, uint32_t *flags)
+{
+    if (mdnid != NULL)
+        *mdnid = siginf->mdnid;
+    if (pknid != NULL)
+        *pknid = siginf->pknid;
+    if (secbits != NULL)
+        *secbits = siginf->secbits;
+    if (flags != NULL)
+        *flags = siginf->flags;
+    return (siginf->flags & X509_SIG_INFO_VALID) != 0;
+}
+
+void X509_SIG_INFO_set(X509_SIG_INFO *siginf, int mdnid, int pknid,
+                       int secbits, uint32_t flags)
+{
+    siginf->mdnid = mdnid;
+    siginf->pknid = pknid;
+    siginf->secbits = secbits;
+    siginf->flags = flags;
+}
+
+int X509_get_signature_info(X509 *x, int *mdnid, int *pknid, int *secbits,
+                            uint32_t *flags)
+{
+    X509_check_purpose(x, -1, -1);
+    return X509_SIG_INFO_get(&x->siginf, mdnid, pknid, secbits, flags);
+}
+
+static void x509_sig_info_init(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
+                               const ASN1_STRING *sig)
+{
+    int pknid, mdnid;
+    const EVP_MD *md;
+
+    siginf->mdnid = NID_undef;
+    siginf->pknid = NID_undef;
+    siginf->secbits = -1;
+    siginf->flags = 0;
+    if (!OBJ_find_sigid_algs(OBJ_obj2nid(alg->algorithm), &mdnid, &pknid)
+            || pknid == NID_undef)
+        return;
+    siginf->pknid = pknid;
+    if (mdnid == NID_undef) {
+        /* If we have one, use a custom handler for this algorithm */
+        const EVP_PKEY_ASN1_METHOD *ameth = EVP_PKEY_asn1_find(NULL, pknid);
+        if (ameth == NULL || ameth->siginf_set == NULL
+                || ameth->siginf_set(siginf, alg, sig) == 0)
+            return;
+        siginf->flags |= X509_SIG_INFO_VALID;
+        return;
+    }
+    siginf->flags |= X509_SIG_INFO_VALID;
+    siginf->mdnid = mdnid;
+    md = EVP_get_digestbynid(mdnid);
+    if (md == NULL)
+        return;
+    /* Security bits: half number of bits in digest */
+    siginf->secbits = EVP_MD_size(md) * 4;
+    switch (mdnid) {
+        case NID_sha1:
+        case NID_sha256:
+        case NID_sha384:
+        case NID_sha512:
+        siginf->flags |= X509_SIG_INFO_TLS;
+    }
+}
+
+void x509_init_sig_info(X509 *x)
+{
+    x509_sig_info_init(&x->siginf, &x->sig_alg, &x->signature);
+}
index fa5c425ffc48a1a93d298402c5e31a8c40a3b6a8..2ff8854ca3c629d1daee2d0ba8301222a75cbf72 100644 (file)
@@ -488,6 +488,7 @@ static void x509v3_cache_extensions(X509 *x)
             break;
         }
     }
+    x509_init_sig_info(x);
     x->ex_flags |= EXFLAG_SET;
 }
 
index 129a67f0579d4b4d644dfea847b7825f1a73846a..deea03899af2a46fc0edaa3084ed6fe975b4461e 100644 (file)
@@ -131,6 +131,8 @@ typedef struct x509_lookup_st X509_LOOKUP;
 typedef struct x509_lookup_method_st X509_LOOKUP_METHOD;
 typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM;
 
+typedef struct x509_sig_info_st X509_SIG_INFO;
+
 typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO;
 
 typedef struct v3_ext_ctx X509V3_CTX;
index a6aabebd9cc0abb45b6306210d275af1a41675d4..0a692f803e64c3235c5ef2fd467ed0d49e64cf26 100644 (file)
 extern "C" {
 #endif
 
+
+/* Flags for X509_get_signature_info() */
+/* Signature info is valid */
+# define X509_SIG_INFO_VALID     0x1
+/* Signature is suitable for TLS use */
+# define X509_SIG_INFO_TLS       0x2
+
 # define X509_FILETYPE_PEM       1
 # define X509_FILETYPE_ASN1      2
 # define X509_FILETYPE_DEFAULT   3
@@ -549,6 +556,14 @@ X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length);
 
 int i2d_re_X509_tbs(X509 *x, unsigned char **pp);
 
+int X509_SIG_INFO_get(const X509_SIG_INFO *siginf, int *mdnid, int *pknid,
+                      int *secbits, uint32_t *flags);
+void X509_SIG_INFO_set(X509_SIG_INFO *siginf, int mdnid, int pknid,
+                       int secbits, uint32_t flags);
+
+int X509_get_signature_info(X509 *x, int *mdnid, int *pknid, int *secbits,
+                            uint32_t *flags);
+
 void X509_get0_signature(const ASN1_BIT_STRING **psig,
                          const X509_ALGOR **palg, const X509 *x);
 int X509_get_signature_nid(const X509 *x);