diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2011-10-09 23:13:50 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2011-10-09 23:13:50 +0000 |
commit | 9309ea66177f927aefa14bf317a578427139a0fc (patch) | |
tree | dde4b5ce742168c5860279a634457045ac562e17 /crypto/asn1 | |
parent | 05c9e3aea584c4d618dc32a4825287f06828a537 (diff) |
Backport PSS signature support from HEAD.
Diffstat (limited to 'crypto/asn1')
-rw-r--r-- | crypto/asn1/a_sign.c | 105 | ||||
-rw-r--r-- | crypto/asn1/a_verify.c | 63 | ||||
-rw-r--r-- | crypto/asn1/asn1.h | 7 | ||||
-rw-r--r-- | crypto/asn1/asn1_err.c | 2 | ||||
-rw-r--r-- | crypto/asn1/asn1_locl.h | 11 | ||||
-rw-r--r-- | crypto/asn1/t_crl.c | 3 | ||||
-rw-r--r-- | crypto/asn1/t_x509.c | 42 |
7 files changed, 167 insertions, 66 deletions
diff --git a/crypto/asn1/a_sign.c b/crypto/asn1/a_sign.c index d96a622d83..7b4a193d6b 100644 --- a/crypto/asn1/a_sign.c +++ b/crypto/asn1/a_sign.c @@ -218,65 +218,100 @@ int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, const EVP_MD *type) { EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + if (!EVP_DigestSignInit(&ctx, NULL, type, NULL, pkey)) + { + EVP_MD_CTX_cleanup(&ctx); + return 0; + } + return ASN1_item_sign_ctx(it, algor1, algor2, signature, asn, &ctx); + } + + +int ASN1_item_sign_ctx(const ASN1_ITEM *it, + X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx) + { + const EVP_MD *type; + EVP_PKEY *pkey; unsigned char *buf_in=NULL,*buf_out=NULL; - int inl=0,outl=0,outll=0; + size_t inl=0,outl=0,outll=0; int signid, paramtype; + int rv; - if (type == NULL) + type = EVP_MD_CTX_md(ctx); + pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + + if (!type || !pkey) { - int def_nid; - if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0) - type = EVP_get_digestbynid(def_nid); + ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ASN1_R_CONTEXT_NOT_INITIALISED); + return 0; } - if (type == NULL) + if (pkey->ameth->item_sign) { - ASN1err(ASN1_F_ASN1_ITEM_SIGN, ASN1_R_NO_DEFAULT_DIGEST); - return 0; + rv = pkey->ameth->item_sign(ctx, it, asn, algor1, algor2, + signature); + if (rv == 1) + outl = signature->length; + /* Return value meanings: + * <=0: error. + * 1: method does everything. + * 2: carry on as normal. + * 3: ASN1 method sets algorithm identifiers: just sign. + */ + if (rv <= 0) + ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, ERR_R_EVP_LIB); + if (rv <= 1) + goto err; } + else + rv = 2; - if (type->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) + if (rv == 2) { - if (!pkey->ameth || - !OBJ_find_sigid_by_algs(&signid, EVP_MD_nid(type), - pkey->ameth->pkey_id)) + if (type->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) { - ASN1err(ASN1_F_ASN1_ITEM_SIGN, - ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); - return 0; + if (!pkey->ameth || + !OBJ_find_sigid_by_algs(&signid, + EVP_MD_nid(type), + pkey->ameth->pkey_id)) + { + ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX, + ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); + return 0; + } } - } - else - signid = type->pkey_type; + else + signid = type->pkey_type; - if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) - paramtype = V_ASN1_NULL; - else - paramtype = V_ASN1_UNDEF; + if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) + paramtype = V_ASN1_NULL; + else + paramtype = V_ASN1_UNDEF; - if (algor1) - X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL); - if (algor2) - X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL); + if (algor1) + X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL); + if (algor2) + X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL); + + } - EVP_MD_CTX_init(&ctx); inl=ASN1_item_i2d(asn,&buf_in, it); outll=outl=EVP_PKEY_size(pkey); - buf_out=(unsigned char *)OPENSSL_malloc((unsigned int)outl); + buf_out=OPENSSL_malloc((unsigned int)outl); if ((buf_in == NULL) || (buf_out == NULL)) { outl=0; - ASN1err(ASN1_F_ASN1_ITEM_SIGN,ERR_R_MALLOC_FAILURE); + ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,ERR_R_MALLOC_FAILURE); goto err; } - if (!EVP_SignInit_ex(&ctx,type, NULL) - || !EVP_SignUpdate(&ctx,(unsigned char *)buf_in,inl) - || !EVP_SignFinal(&ctx,(unsigned char *)buf_out, - (unsigned int *)&outl,pkey)) + if (!EVP_DigestSignUpdate(ctx, buf_in, inl) + || !EVP_DigestSignFinal(ctx, buf_out, &outl)) { outl=0; - ASN1err(ASN1_F_ASN1_ITEM_SIGN,ERR_R_EVP_LIB); + ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,ERR_R_EVP_LIB); goto err; } if (signature->data != NULL) OPENSSL_free(signature->data); @@ -289,7 +324,7 @@ int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); signature->flags|=ASN1_STRING_FLAG_BITS_LEFT; err: - EVP_MD_CTX_cleanup(&ctx); + EVP_MD_CTX_cleanup(ctx); if (buf_in != NULL) { OPENSSL_cleanse((char *)buf_in,(unsigned int)inl); OPENSSL_free(buf_in); } if (buf_out != NULL) diff --git a/crypto/asn1/a_verify.c b/crypto/asn1/a_verify.c index d9332ee15d..432722e409 100644 --- a/crypto/asn1/a_verify.c +++ b/crypto/asn1/a_verify.c @@ -131,11 +131,10 @@ err: #endif -int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signature, - void *asn, EVP_PKEY *pkey) +int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, + ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) { EVP_MD_CTX ctx; - const EVP_MD *type = NULL; unsigned char *buf_in=NULL; int ret= -1,inl; @@ -149,25 +148,47 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); goto err; } - type=EVP_get_digestbynid(mdnid); - if (type == NULL) + if (mdnid == NID_undef) { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); - goto err; + if (!pkey->ameth || !pkey->ameth->item_verify) + { + ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM); + goto err; + } + ret = pkey->ameth->item_verify(&ctx, it, asn, a, + signature, pkey); + /* Return value of 2 means carry on, anything else means we + * exit straight away: either a fatal error of the underlying + * verification routine handles all verification. + */ + if (ret != 2) + goto err; + ret = -1; } - - /* Check public key OID matches public key type */ - if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) + else { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE); - goto err; - } + const EVP_MD *type; + type=EVP_get_digestbynid(mdnid); + if (type == NULL) + { + ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + goto err; + } + + /* Check public key OID matches public key type */ + if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) + { + ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ASN1_R_WRONG_PUBLIC_KEY_TYPE); + goto err; + } + + if (!EVP_DigestVerifyInit(&ctx, NULL, type, NULL, pkey)) + { + ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB); + ret=0; + goto err; + } - if (!EVP_VerifyInit_ex(&ctx,type, NULL)) - { - ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB); - ret=0; - goto err; } inl = ASN1_item_i2d(asn, &buf_in, it); @@ -178,7 +199,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat goto err; } - if (!EVP_VerifyUpdate(&ctx,(unsigned char *)buf_in,inl)) + if (!EVP_DigestVerifyUpdate(&ctx,buf_in,inl)) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB); ret=0; @@ -188,8 +209,8 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, ASN1_BIT_STRING *signat OPENSSL_cleanse(buf_in,(unsigned int)inl); OPENSSL_free(buf_in); - if (EVP_VerifyFinal(&ctx,(unsigned char *)signature->data, - (unsigned int)signature->length,pkey) <= 0) + if (EVP_DigestVerifyFinal(&ctx,signature->data, + (size_t)signature->length) <= 0) { ASN1err(ASN1_F_ASN1_ITEM_VERIFY,ERR_R_EVP_LIB); ret=0; diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h index 439e76044a..220a0c8c63 100644 --- a/crypto/asn1/asn1.h +++ b/crypto/asn1/asn1.h @@ -235,7 +235,7 @@ typedef struct asn1_object_st */ #define ASN1_STRING_FLAG_MSTRING 0x040 /* This is the base type that holds just about everything :-) */ -typedef struct asn1_string_st +struct asn1_string_st { int length; int type; @@ -245,7 +245,7 @@ typedef struct asn1_string_st * input data has a non-zero 'unused bits' value, it will be * handled correctly */ long flags; - } ASN1_STRING; + }; /* ASN1_ENCODING structure: this is used to save the received * encoding of an ASN1 type. This is useful to get round @@ -293,7 +293,6 @@ DECLARE_STACK_OF(ASN1_STRING_TABLE) * see asn1t.h */ typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE; -typedef struct ASN1_ITEM_st ASN1_ITEM; typedef struct ASN1_TLC_st ASN1_TLC; /* This is just an opaque pointer */ typedef struct ASN1_VALUE_st ASN1_VALUE; @@ -1194,6 +1193,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_F_ASN1_ITEM_I2D_FP 193 #define ASN1_F_ASN1_ITEM_PACK 198 #define ASN1_F_ASN1_ITEM_SIGN 195 +#define ASN1_F_ASN1_ITEM_SIGN_CTX 220 #define ASN1_F_ASN1_ITEM_UNPACK 199 #define ASN1_F_ASN1_ITEM_VERIFY 197 #define ASN1_F_ASN1_MBSTRING_NCOPY 122 @@ -1292,6 +1292,7 @@ void ERR_load_ASN1_strings(void); #define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 #define ASN1_R_BUFFER_TOO_SMALL 107 #define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 108 +#define ASN1_R_CONTEXT_NOT_INITIALISED 217 #define ASN1_R_DATA_IS_WRONG 109 #define ASN1_R_DECODE_ERROR 110 #define ASN1_R_DECODING_ERROR 111 diff --git a/crypto/asn1/asn1_err.c b/crypto/asn1/asn1_err.c index 7e209956e6..1a30bf119b 100644 --- a/crypto/asn1/asn1_err.c +++ b/crypto/asn1/asn1_err.c @@ -107,6 +107,7 @@ static ERR_STRING_DATA ASN1_str_functs[]= {ERR_FUNC(ASN1_F_ASN1_ITEM_I2D_FP), "ASN1_item_i2d_fp"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_PACK), "ASN1_item_pack"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_SIGN), "ASN1_item_sign"}, +{ERR_FUNC(ASN1_F_ASN1_ITEM_SIGN_CTX), "ASN1_item_sign_ctx"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_UNPACK), "ASN1_item_unpack"}, {ERR_FUNC(ASN1_F_ASN1_ITEM_VERIFY), "ASN1_item_verify"}, {ERR_FUNC(ASN1_F_ASN1_MBSTRING_NCOPY), "ASN1_mbstring_ncopy"}, @@ -208,6 +209,7 @@ static ERR_STRING_DATA ASN1_str_reasons[]= {ERR_REASON(ASN1_R_BOOLEAN_IS_WRONG_LENGTH),"boolean is wrong length"}, {ERR_REASON(ASN1_R_BUFFER_TOO_SMALL) ,"buffer too small"}, {ERR_REASON(ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER),"cipher has no object identifier"}, +{ERR_REASON(ASN1_R_CONTEXT_NOT_INITIALISED),"context not initialised"}, {ERR_REASON(ASN1_R_DATA_IS_WRONG) ,"data is wrong"}, {ERR_REASON(ASN1_R_DECODE_ERROR) ,"decode error"}, {ERR_REASON(ASN1_R_DECODING_ERROR) ,"decoding error"}, diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h index 5aa65e28f5..9fcf0d9530 100644 --- a/crypto/asn1/asn1_locl.h +++ b/crypto/asn1/asn1_locl.h @@ -102,6 +102,10 @@ struct evp_pkey_asn1_method_st int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); + int (*sig_print)(BIO *out, + const X509_ALGOR *sigalg, const ASN1_STRING *sig, + int indent, ASN1_PCTX *pctx); + void (*pkey_free)(EVP_PKEY *pkey); int (*pkey_ctrl)(EVP_PKEY *pkey, int op, long arg1, void *arg2); @@ -111,6 +115,13 @@ struct evp_pkey_asn1_method_st int (*old_priv_decode)(EVP_PKEY *pkey, const unsigned char **pder, int derlen); int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder); + /* Custom ASN1 signature verification */ + int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, + X509_ALGOR *a, ASN1_BIT_STRING *sig, + EVP_PKEY *pkey); + int (*item_sign)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, + X509_ALGOR *alg1, X509_ALGOR *alg2, + ASN1_BIT_STRING *sig); } /* EVP_PKEY_ASN1_METHOD */; diff --git a/crypto/asn1/t_crl.c b/crypto/asn1/t_crl.c index ee5a687ce8..c61169208a 100644 --- a/crypto/asn1/t_crl.c +++ b/crypto/asn1/t_crl.c @@ -94,8 +94,7 @@ int X509_CRL_print(BIO *out, X509_CRL *x) l = X509_CRL_get_version(x); BIO_printf(out, "%8sVersion %lu (0x%lx)\n", "", l+1, l); i = OBJ_obj2nid(x->sig_alg->algorithm); - BIO_printf(out, "%8sSignature Algorithm: %s\n", "", - (i == NID_undef) ? "NONE" : OBJ_nid2ln(i)); + X509_signature_print(out, x->sig_alg, NULL); p=X509_NAME_oneline(X509_CRL_get_issuer(x),NULL,0); BIO_printf(out,"%8sIssuer: %s\n","",p); OPENSSL_free(p); diff --git a/crypto/asn1/t_x509.c b/crypto/asn1/t_x509.c index 01cf9e427a..db88f3a3e1 100644 --- a/crypto/asn1/t_x509.c +++ b/crypto/asn1/t_x509.c @@ -72,6 +72,7 @@ #include <openssl/objects.h> #include <openssl/x509.h> #include <openssl/x509v3.h> +#include "asn1_locl.h" #ifndef OPENSSL_NO_FP_API int X509_print_fp(FILE *fp, X509 *x) @@ -167,12 +168,16 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, unsigned long cflag) if(!(cflag & X509_FLAG_NO_SIGNAME)) { + if(X509_signature_print(bp, x->sig_alg, NULL) <= 0) + goto err; +#if 0 if (BIO_printf(bp,"%8sSignature Algorithm: ","") <= 0) goto err; if (i2a_ASN1_OBJECT(bp, ci->signature->algorithm) <= 0) goto err; if (BIO_puts(bp, "\n") <= 0) goto err; +#endif } if(!(cflag & X509_FLAG_NO_ISSUER)) @@ -286,23 +291,50 @@ err: return(0); } -int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig) +int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent) { - unsigned char *s; + const unsigned char *s; int i, n; - if (BIO_puts(bp," Signature Algorithm: ") <= 0) return 0; - if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0; n=sig->length; s=sig->data; for (i=0; i<n; i++) { if ((i%18) == 0) - if (BIO_write(bp,"\n ",9) <= 0) return 0; + { + if (BIO_write(bp,"\n",1) <= 0) return 0; + if (BIO_indent(bp, indent, indent) <= 0) return 0; + } if (BIO_printf(bp,"%02x%s",s[i], ((i+1) == n)?"":":") <= 0) return 0; } if (BIO_write(bp,"\n",1) != 1) return 0; + + return 1; +} + +int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig) +{ + int sig_nid; + if (BIO_puts(bp," Signature Algorithm: ") <= 0) return 0; + if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0; + + sig_nid = OBJ_obj2nid(sigalg->algorithm); + if (sig_nid != NID_undef) + { + int pkey_nid, dig_nid; + const EVP_PKEY_ASN1_METHOD *ameth; + if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) + { + ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); + if (ameth && ameth->sig_print) + return ameth->sig_print(bp, sigalg, sig, 9, 0); + } + } + if (sig) + return X509_signature_dump(bp, sig, 9); + else if (BIO_puts(bp, "\n") <= 0) + return 0; return 1; } |