diff options
author | Brian Carlstrom <bdc@google.com> | 2012-03-12 15:30:37 -0700 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2012-03-12 16:19:22 -0700 |
commit | 21c841450af61d0a9119cdc863e93d019127bfe1 (patch) | |
tree | 4ea5e41f6bc6e5de4e1fa9afb41ce1d68d078547 /crypto | |
parent | 48ab0d92457e1d77588be52be12076e372fdbcb7 (diff) | |
download | replicant_openssl-21c841450af61d0a9119cdc863e93d019127bfe1.zip replicant_openssl-21c841450af61d0a9119cdc863e93d019127bfe1.tar.gz replicant_openssl-21c841450af61d0a9119cdc863e93d019127bfe1.tar.bz2 |
Upgrade to openssl-1.0.0h
Change-Id: I0bc9b6b486bf10ebae34b994b63cf6011afdf5e1
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/asn1/asn_mime.c | 17 | ||||
-rw-r--r-- | crypto/asn1/x_name.c | 3 | ||||
-rw-r--r-- | crypto/asn1/x_pubkey.c | 11 | ||||
-rw-r--r-- | crypto/bio/bio.h | 1 | ||||
-rw-r--r-- | crypto/bio/bss_dgram.c | 21 | ||||
-rw-r--r-- | crypto/engine/eng_cryptodev.c | 71 | ||||
-rw-r--r-- | crypto/opensslv.h | 6 | ||||
-rwxr-xr-x | crypto/perlasm/x86_64-xlate.pl | 3 | ||||
-rw-r--r-- | crypto/pkcs12/p12_kiss.c | 2 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_doit.c | 65 | ||||
-rw-r--r-- | crypto/pkcs7/pk7_smime.c | 25 | ||||
-rw-r--r-- | crypto/ui/ui_openssl.c | 2 | ||||
-rw-r--r-- | crypto/x509/x509_vfy.c | 5 | ||||
-rw-r--r-- | crypto/x509v3/v3_asid.c | 63 |
14 files changed, 228 insertions, 67 deletions
diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c index bbc4952..54a704a 100644 --- a/crypto/asn1/asn_mime.c +++ b/crypto/asn1/asn_mime.c @@ -377,8 +377,12 @@ static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, BIO *tmpbio; const ASN1_AUX *aux = it->funcs; ASN1_STREAM_ARG sarg; + int rv = 1; - if (!(flags & SMIME_DETACHED)) + /* If data is not deteched or resigning then the output BIO is + * already set up to finalise when it is written through. + */ + if (!(flags & SMIME_DETACHED) || (flags & PKCS7_REUSE_DIGEST)) { SMIME_crlf_copy(data, out, flags); return 1; @@ -405,7 +409,7 @@ static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, /* Finalize structure */ if (aux->asn1_cb(ASN1_OP_DETACHED_POST, &val, it, &sarg) <= 0) - return 0; + rv = 0; /* Now remove any digests prepended to the BIO */ @@ -416,7 +420,7 @@ static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags, sarg.ndef_bio = tmpbio; } - return 1; + return rv; } @@ -486,9 +490,9 @@ ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it) if(strcmp(hdr->value, "application/x-pkcs7-signature") && strcmp(hdr->value, "application/pkcs7-signature")) { - sk_MIME_HEADER_pop_free(headers, mime_hdr_free); ASN1err(ASN1_F_SMIME_READ_ASN1,ASN1_R_SIG_INVALID_MIME_TYPE); ERR_add_error_data(2, "type: ", hdr->value); + sk_MIME_HEADER_pop_free(headers, mime_hdr_free); sk_BIO_pop_free(parts, BIO_vfree); return NULL; } @@ -858,12 +862,17 @@ static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value) static int mime_hdr_cmp(const MIME_HEADER * const *a, const MIME_HEADER * const *b) { + if (!(*a)->name || !(*b)->name) + return !!(*a)->name - !!(*b)->name; + return(strcmp((*a)->name, (*b)->name)); } static int mime_param_cmp(const MIME_PARAM * const *a, const MIME_PARAM * const *b) { + if (!(*a)->param_name || !(*b)->param_name) + return !!(*a)->param_name - !!(*b)->param_name; return(strcmp((*a)->param_name, (*b)->param_name)); } diff --git a/crypto/asn1/x_name.c b/crypto/asn1/x_name.c index 49be08b..d7c2318 100644 --- a/crypto/asn1/x_name.c +++ b/crypto/asn1/x_name.c @@ -399,8 +399,7 @@ static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in) /* If type not in bitmask just copy string across */ if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON)) { - out->type = in->type; - if (!ASN1_STRING_set(out, in->data, in->length)) + if (!ASN1_STRING_copy(out, in)) return 0; return 1; } diff --git a/crypto/asn1/x_pubkey.c b/crypto/asn1/x_pubkey.c index d42b6a2..627ec87 100644 --- a/crypto/asn1/x_pubkey.c +++ b/crypto/asn1/x_pubkey.c @@ -171,7 +171,16 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) goto error; } - key->pkey = ret; + /* Check to see if another thread set key->pkey first */ + CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY); + if (key->pkey) + { + EVP_PKEY_free(ret); + ret = key->pkey; + } + else + key->pkey = ret; + CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY); CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_EVP_PKEY); return ret; diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h index ab47abc..3c39d18 100644 --- a/crypto/bio/bio.h +++ b/crypto/bio/bio.h @@ -146,6 +146,7 @@ extern "C" { /* #endif */ #define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */ +#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47 #define BIO_CTRL_DGRAM_GET_MTU 41 /* get cached value for MTU */ #define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for * MTU. want to use this diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c index 71ebe98..ad9c372 100644 --- a/crypto/bio/bss_dgram.c +++ b/crypto/bio/bss_dgram.c @@ -547,6 +547,27 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) ret = 0; #endif break; + case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: + switch (data->peer.sa.sa_family) + { + case AF_INET: + ret = 576 - 20 - 8; + break; +#if OPENSSL_USE_IPV6 + case AF_INET6: +#ifdef IN6_IS_ADDR_V4MAPPED + if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) + ret = 576 - 20 - 8; + else +#endif + ret = 1280 - 40 - 8; + break; +#endif + default: + ret = 576 - 20 - 8; + break; + } + break; case BIO_CTRL_DGRAM_GET_MTU: return data->mtu; break; diff --git a/crypto/engine/eng_cryptodev.c b/crypto/engine/eng_cryptodev.c index 52f4ca3..5a715ac 100644 --- a/crypto/engine/eng_cryptodev.c +++ b/crypto/engine/eng_cryptodev.c @@ -79,8 +79,6 @@ struct dev_crypto_state { unsigned char digest_res[HASH_MAX_LEN]; char *mac_data; int mac_len; - - int copy; #endif }; @@ -200,6 +198,7 @@ get_dev_crypto(void) if ((fd = open_dev_crypto()) == -1) return (-1); +#ifndef CRIOGET_NOT_NEEDED if (ioctl(fd, CRIOGET, &retfd) == -1) return (-1); @@ -208,9 +207,19 @@ get_dev_crypto(void) close(retfd); return (-1); } +#else + retfd = fd; +#endif return (retfd); } +static void put_dev_crypto(int fd) +{ +#ifndef CRIOGET_NOT_NEEDED + close(fd); +#endif +} + /* Caching version for asym operations */ static int get_asym_dev_crypto(void) @@ -252,7 +261,7 @@ get_cryptodev_ciphers(const int **cnids) ioctl(fd, CIOCFSESSION, &sess.ses) != -1) nids[count++] = ciphers[i].nid; } - close(fd); + put_dev_crypto(fd); if (count > 0) *cnids = nids; @@ -291,7 +300,7 @@ get_cryptodev_digests(const int **cnids) ioctl(fd, CIOCFSESSION, &sess.ses) != -1) nids[count++] = digests[i].nid; } - close(fd); + put_dev_crypto(fd); if (count > 0) *cnids = nids; @@ -436,7 +445,7 @@ cryptodev_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, sess->cipher = cipher; if (ioctl(state->d_fd, CIOCGSESSION, sess) == -1) { - close(state->d_fd); + put_dev_crypto(state->d_fd); state->d_fd = -1; return (0); } @@ -473,7 +482,7 @@ cryptodev_cleanup(EVP_CIPHER_CTX *ctx) } else { ret = 1; } - close(state->d_fd); + put_dev_crypto(state->d_fd); state->d_fd = -1; return (ret); @@ -686,7 +695,7 @@ static int cryptodev_digest_init(EVP_MD_CTX *ctx) sess->mac = digest; if (ioctl(state->d_fd, CIOCGSESSION, sess) < 0) { - close(state->d_fd); + put_dev_crypto(state->d_fd); state->d_fd = -1; printf("cryptodev_digest_init: Open session failed\n"); return (0); @@ -758,14 +767,12 @@ static int cryptodev_digest_final(EVP_MD_CTX *ctx, unsigned char *md) if (! (ctx->flags & EVP_MD_CTX_FLAG_ONESHOT) ) { /* if application doesn't support one buffer */ memset(&cryp, 0, sizeof(cryp)); - cryp.ses = sess->ses; cryp.flags = 0; cryp.len = state->mac_len; cryp.src = state->mac_data; cryp.dst = NULL; cryp.mac = (caddr_t)md; - if (ioctl(state->d_fd, CIOCCRYPT, &cryp) < 0) { printf("cryptodev_digest_final: digest failed\n"); return (0); @@ -786,6 +793,9 @@ static int cryptodev_digest_cleanup(EVP_MD_CTX *ctx) struct dev_crypto_state *state = ctx->md_data; struct session_op *sess = &state->d_sess; + if (state == NULL) + return 0; + if (state->d_fd < 0) { printf("cryptodev_digest_cleanup: illegal input\n"); return (0); @@ -797,16 +807,13 @@ static int cryptodev_digest_cleanup(EVP_MD_CTX *ctx) state->mac_len = 0; } - if (state->copy) - return 1; - if (ioctl(state->d_fd, CIOCFSESSION, &sess->ses) < 0) { printf("cryptodev_digest_cleanup: failed to close session\n"); ret = 0; } else { ret = 1; } - close(state->d_fd); + put_dev_crypto(state->d_fd); state->d_fd = -1; return (ret); @@ -816,15 +823,39 @@ static int cryptodev_digest_copy(EVP_MD_CTX *to,const EVP_MD_CTX *from) { struct dev_crypto_state *fstate = from->md_data; struct dev_crypto_state *dstate = to->md_data; + struct session_op *sess; + int digest; - memcpy(dstate, fstate, sizeof(struct dev_crypto_state)); + if (dstate == NULL || fstate == NULL) + return 1; - if (fstate->mac_len != 0) { - dstate->mac_data = OPENSSL_malloc(fstate->mac_len); - memcpy(dstate->mac_data, fstate->mac_data, fstate->mac_len); + memcpy(dstate, fstate, sizeof(struct dev_crypto_state)); + + sess = &dstate->d_sess; + + digest = digest_nid_to_cryptodev(to->digest->type); + + sess->mackey = dstate->dummy_mac_key; + sess->mackeylen = digest_key_length(to->digest->type); + sess->mac = digest; + + dstate->d_fd = get_dev_crypto(); + + if (ioctl(dstate->d_fd, CIOCGSESSION, sess) < 0) { + put_dev_crypto(dstate->d_fd); + dstate->d_fd = -1; + printf("cryptodev_digest_init: Open session failed\n"); + return (0); } - dstate->copy = 1; + if (fstate->mac_len != 0) { + if (fstate->mac_data != NULL) + { + dstate->mac_data = OPENSSL_malloc(fstate->mac_len); + memcpy(dstate->mac_data, fstate->mac_data, fstate->mac_len); + dstate->mac_len = fstate->mac_len; + } + } return 1; } @@ -1347,11 +1378,11 @@ ENGINE_load_cryptodev(void) * find out what asymmetric crypto algorithms we support */ if (ioctl(fd, CIOCASYMFEAT, &cryptodev_asymfeat) == -1) { - close(fd); + put_dev_crypto(fd); ENGINE_free(engine); return; } - close(fd); + put_dev_crypto(fd); if (!ENGINE_set_id(engine, "cryptodev") || !ENGINE_set_name(engine, "BSD cryptodev engine") || diff --git a/crypto/opensslv.h b/crypto/opensslv.h index a368f6f..66a6d0d 100644 --- a/crypto/opensslv.h +++ b/crypto/opensslv.h @@ -25,11 +25,11 @@ * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for * major minor fix final patch/beta) */ -#define OPENSSL_VERSION_NUMBER 0x1000007fL +#define OPENSSL_VERSION_NUMBER 0x1000008fL #ifdef OPENSSL_FIPS -#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.0g-fips 18 Jan 2012" +#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.0h-fips 12 Mar 2012" #else -#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.0g 18 Jan 2012" +#define OPENSSL_VERSION_TEXT "OpenSSL 1.0.0h 12 Mar 2012" #endif #define OPENSSL_VERSION_PTEXT " part of " OPENSSL_VERSION_TEXT diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl index e47116b..674da3b 100755 --- a/crypto/perlasm/x86_64-xlate.pl +++ b/crypto/perlasm/x86_64-xlate.pl @@ -555,7 +555,8 @@ my %globals; $v.=" READONLY"; $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref); } elsif ($line=~/\.CRT\$/i) { - $v.=" READONLY DWORD"; + $v.=" READONLY "; + $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD"; } } $current_segment = $line; diff --git a/crypto/pkcs12/p12_kiss.c b/crypto/pkcs12/p12_kiss.c index 292cc3e..206b1b0 100644 --- a/crypto/pkcs12/p12_kiss.c +++ b/crypto/pkcs12/p12_kiss.c @@ -167,7 +167,7 @@ int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, if (cert && *cert) X509_free(*cert); if (x) - X509_free(*cert); + X509_free(x); if (ocerts) sk_X509_pop_free(ocerts, X509_free); return 0; diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c index 3bf1a36..e4b095e 100644 --- a/crypto/pkcs7/pk7_doit.c +++ b/crypto/pkcs7/pk7_doit.c @@ -204,11 +204,11 @@ static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, unsigned char *ek = NULL; size_t eklen; - int ret = 0; + int ret = -1; pctx = EVP_PKEY_CTX_new(pkey, NULL); if (!pctx) - return 0; + return -1; if (EVP_PKEY_decrypt_init(pctx) <= 0) goto err; @@ -235,12 +235,19 @@ static int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen, if (EVP_PKEY_decrypt(pctx, ek, &eklen, ri->enc_key->data, ri->enc_key->length) <= 0) { + ret = 0; PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB); goto err; } ret = 1; + if (*pek) + { + OPENSSL_cleanse(*pek, *peklen); + OPENSSL_free(*pek); + } + *pek = ek; *peklen = eklen; @@ -500,8 +507,8 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) int max; X509_OBJECT ret; #endif - unsigned char *ek = NULL; - int eklen; + unsigned char *ek = NULL, *tkey = NULL; + int eklen, tkeylen; if ((etmp=BIO_new(BIO_f_cipher())) == NULL) { @@ -534,29 +541,28 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) } /* If we haven't got a certificate try each ri in turn */ - if (pcert == NULL) { + /* Always attempt to decrypt all rinfo even + * after sucess as a defence against MMA timing + * attacks. + */ for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) { ri=sk_PKCS7_RECIP_INFO_value(rsk,i); + if (pkcs7_decrypt_rinfo(&ek, &eklen, - ri, pkey) > 0) - break; + ri, pkey) < 0) + goto err; ERR_clear_error(); - ri = NULL; - } - if (ri == NULL) - { - PKCS7err(PKCS7_F_PKCS7_DATADECODE, - PKCS7_R_NO_RECIPIENT_MATCHES_KEY); - goto err; } } else { - if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) <= 0) + /* Only exit on fatal errors, not decrypt failure */ + if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0) goto err; + ERR_clear_error(); } evp_ctx=NULL; @@ -565,6 +571,19 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) goto err; if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) goto err; + /* Generate random key as MMA defence */ + tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx); + tkey = OPENSSL_malloc(tkeylen); + if (!tkey) + goto err; + if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) + goto err; + if (ek == NULL) + { + ek = tkey; + eklen = tkeylen; + tkey = NULL; + } if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) { /* Some S/MIME clients don't use the same key @@ -573,11 +592,16 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) */ if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) { - PKCS7err(PKCS7_F_PKCS7_DATADECODE, - PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH); - goto err; + /* Use random key as MMA defence */ + OPENSSL_cleanse(ek, eklen); + OPENSSL_free(ek); + ek = tkey; + eklen = tkeylen; + tkey = NULL; } } + /* Clear errors so we don't leak information useful in MMA */ + ERR_clear_error(); if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0) goto err; @@ -586,6 +610,11 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert) OPENSSL_cleanse(ek,eklen); OPENSSL_free(ek); } + if (tkey) + { + OPENSSL_cleanse(tkey,tkeylen); + OPENSSL_free(tkey); + } if (out == NULL) out=etmp; diff --git a/crypto/pkcs7/pk7_smime.c b/crypto/pkcs7/pk7_smime.c index 86742d0..a5104f8 100644 --- a/crypto/pkcs7/pk7_smime.c +++ b/crypto/pkcs7/pk7_smime.c @@ -573,15 +573,34 @@ int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags) return 0; } ret = SMIME_text(bread, data); + if (ret > 0 && BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) + { + if (!BIO_get_cipher_status(tmpmem)) + ret = 0; + } BIO_free_all(bread); return ret; } else { for(;;) { i = BIO_read(tmpmem, buf, sizeof(buf)); - if(i <= 0) break; - BIO_write(data, buf, i); + if(i <= 0) + { + ret = 1; + if (BIO_method_type(tmpmem) == BIO_TYPE_CIPHER) + { + if (!BIO_get_cipher_status(tmpmem)) + ret = 0; + } + + break; + } + if (BIO_write(data, buf, i) != i) + { + ret = 0; + break; + } } BIO_free_all(tmpmem); - return 1; + return ret; } } diff --git a/crypto/ui/ui_openssl.c b/crypto/ui/ui_openssl.c index b05cbf3..7165cb4 100644 --- a/crypto/ui/ui_openssl.c +++ b/crypto/ui/ui_openssl.c @@ -122,7 +122,7 @@ * sigaction and fileno included. -pedantic would be more appropriate for * the intended purposes, but we can't prevent users from adding -ansi. */ -#ifndef _POSIX_C_SOURCE +#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) #define _POSIX_C_SOURCE 2 #endif #include <signal.h> diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 701ec56..b0779db 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -153,7 +153,6 @@ static int x509_subject_cmp(X509 **a, X509 **b) int X509_verify_cert(X509_STORE_CTX *ctx) { X509 *x,*xtmp,*chain_ss=NULL; - X509_NAME *xn; int bad_chain = 0; X509_VERIFY_PARAM *param = ctx->param; int depth,i,ok=0; @@ -205,7 +204,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) */ /* If we are self signed, we break */ - xn=X509_get_issuer_name(x); if (ctx->check_issued(ctx, x,x)) break; /* If we were passed a cert chain, use it first */ @@ -242,7 +240,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) i=sk_X509_num(ctx->chain); x=sk_X509_value(ctx->chain,i-1); - xn = X509_get_subject_name(x); if (ctx->check_issued(ctx, x, x)) { /* we have a self signed certificate */ @@ -291,7 +288,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) if (depth < num) break; /* If we are self signed, we break */ - xn=X509_get_issuer_name(x); if (ctx->check_issued(ctx,x,x)) break; ok = ctx->get_issuer(&xtmp, ctx, x); @@ -310,7 +306,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx) } /* we now have our chain, lets check it... */ - xn=X509_get_issuer_name(x); /* Is last certificate looked up self signed? */ if (!ctx->check_issued(ctx,x,x)) diff --git a/crypto/x509v3/v3_asid.c b/crypto/x509v3/v3_asid.c index 3f434c0..1587e8e 100644 --- a/crypto/x509v3/v3_asid.c +++ b/crypto/x509v3/v3_asid.c @@ -358,6 +358,20 @@ static int ASIdentifierChoice_is_canonical(ASIdentifierChoice *choice) goto done; } + /* + * Check for inverted range. + */ + i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; + { + ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i); + ASN1_INTEGER *a_min, *a_max; + if (a != NULL && a->type == ASIdOrRange_range) { + extract_min_max(a, &a_min, &a_max); + if (ASN1_INTEGER_cmp(a_min, a_max) > 0) + goto done; + } + } + ret = 1; done: @@ -392,9 +406,18 @@ static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice) return 1; /* - * We have a list. Sort it. + * If not a list, or if empty list, it's broken. + */ + if (choice->type != ASIdentifierChoice_asIdsOrRanges || + sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0) { + X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE, + X509V3_R_EXTENSION_VALUE_ERROR); + return 0; + } + + /* + * We have a non-empty list. Sort it. */ - OPENSSL_assert(choice->type == ASIdentifierChoice_asIdsOrRanges); sk_ASIdOrRange_sort(choice->u.asIdsOrRanges); /* @@ -415,6 +438,13 @@ static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice) OPENSSL_assert(ASN1_INTEGER_cmp(a_min, b_min) <= 0); /* + * Punt inverted ranges. + */ + if (ASN1_INTEGER_cmp(a_min, a_max) > 0 || + ASN1_INTEGER_cmp(b_min, b_max) > 0) + goto done; + + /* * Check for overlaps. */ if (ASN1_INTEGER_cmp(a_max, b_min) >= 0) { @@ -465,12 +495,26 @@ static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice) break; } ASIdOrRange_free(b); - sk_ASIdOrRange_delete(choice->u.asIdsOrRanges, i + 1); + (void) sk_ASIdOrRange_delete(choice->u.asIdsOrRanges, i + 1); i--; continue; } } + /* + * Check for final inverted range. + */ + i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; + { + ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i); + ASN1_INTEGER *a_min, *a_max; + if (a != NULL && a->type == ASIdOrRange_range) { + extract_min_max(a, &a_min, &a_max); + if (ASN1_INTEGER_cmp(a_min, a_max) > 0) + goto done; + } + } + OPENSSL_assert(ASIdentifierChoice_is_canonical(choice)); /* Paranoia */ ret = 1; @@ -498,6 +542,7 @@ static void *v2i_ASIdentifiers(const struct v3_ext_method *method, struct v3_ext_ctx *ctx, STACK_OF(CONF_VALUE) *values) { + ASN1_INTEGER *min = NULL, *max = NULL; ASIdentifiers *asid = NULL; int i; @@ -508,7 +553,6 @@ static void *v2i_ASIdentifiers(const struct v3_ext_method *method, for (i = 0; i < sk_CONF_VALUE_num(values); i++) { CONF_VALUE *val = sk_CONF_VALUE_value(values, i); - ASN1_INTEGER *min = NULL, *max = NULL; int i1, i2, i3, is_range, which; /* @@ -578,18 +622,19 @@ static void *v2i_ASIdentifiers(const struct v3_ext_method *method, max = s2i_ASN1_INTEGER(NULL, s + i2); OPENSSL_free(s); if (min == NULL || max == NULL) { - ASN1_INTEGER_free(min); - ASN1_INTEGER_free(max); X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE); goto err; } + if (ASN1_INTEGER_cmp(min, max) > 0) { + X509V3err(X509V3_F_V2I_ASIDENTIFIERS, X509V3_R_EXTENSION_VALUE_ERROR); + goto err; + } } if (!v3_asid_add_id_or_range(asid, which, min, max)) { - ASN1_INTEGER_free(min); - ASN1_INTEGER_free(max); X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE); goto err; } + min = max = NULL; } /* @@ -601,6 +646,8 @@ static void *v2i_ASIdentifiers(const struct v3_ext_method *method, err: ASIdentifiers_free(asid); + ASN1_INTEGER_free(min); + ASN1_INTEGER_free(max); return NULL; } |