diff --git a/.github/workflows/cross-compiles.yml b/.github/workflows/cross-compiles.yml index 79af07c7016786a0c0140b050ffc4e6fb23f9453..21683b731dffd3d61907df5af201d604c1a92080 100644 --- a/.github/workflows/cross-compiles.yml +++ b/.github/workflows/cross-compiles.yml @@ -183,15 +183,15 @@ jobs: run: make -s -j4 - name: install qemu - if: github.event_name == 'push' && matrix.platform.tests != 'none' + if: matrix.platform.tests != 'none' run: sudo apt-get -yq --force-yes install qemu-user - name: Set QEMU environment - if: github.event_name == 'push' && matrix.platform.qemucpu != '' + if: matrix.platform.qemucpu != '' run: echo "QEMU_CPU=${{ matrix.platform.qemucpu }}" >> $GITHUB_ENV - name: Set OpenSSL caps environment - if: github.event_name == 'push' && matrix.platform.opensslcapsname != '' + if: matrix.platform.opensslcapsname != '' run: echo "OPENSSL_${{ matrix.platform.opensslcapsname }}=\ ${{ matrix.platform.opensslcaps }}" >> $GITHUB_ENV @@ -210,3 +210,9 @@ jobs: make test HARNESS_JOBS=${HARNESS_JOBS:-4} \ TESTS="${{ matrix.platform.tests }} -test_afalg" \ QEMU_LD_PREFIX=/usr/${{ matrix.platform.arch }} + - name: make evp tests + if: github.event_name == 'pull_request' && matrix.platform.tests != 'none' + run: | + make test HARNESS_JOBS=${HARNESS_JOBS:-4} \ + TESTS="test_evp*" \ + QEMU_LD_PREFIX=/usr/${{ matrix.platform.arch }} diff --git a/CHANGES.md b/CHANGES.md index e7f9dc4c8aedff12efaaeb893ce27c1d2b52b783..81044b3d7078da6efb25cee598904131ca2e7d12 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,11 @@ OpenSSL CHANGES =============== -This is a high-level summary of the most important changes. -For a full list of changes, see the [git commit log][log] and -pick the appropriate release branch. +This is a detailed breakdown of significant changes. For a high-level overview +of changes in each release, see [NEWS.md](./NEWS.md). + +For a full list of changes, see the [git commit log][log] and pick the +appropriate release branch. [log]: https://github.com/openssl/openssl/commits/ @@ -26,6 +28,11 @@ OpenSSL 3.3 ### Changes between 3.2 and 3.3 [xx XXX xxxx] + * In `openssl speed`, changed the default hash function used with `hmac` from + `md5` to `sha256`. + + *James Muir* + * The build of exporters (such as `.pc` files for pkg-config) cleaned up to be less hard coded in the build file templates, and to allow easier addition of more exporters. With that, an exporter for CMake is also diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 13a5d63695fee3b6fa83d9b91eeca463983567e3..0117fce16fede75835bb829e51254c8412f72261 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,9 +22,20 @@ guidelines: 1. Anything other than a trivial contribution requires a [Contributor License Agreement] (CLA), giving us permission to use your code. If your contribution is too small to require a CLA (e.g. fixing a spelling - mistake), place the text "`CLA: trivial`" on a line by itself separated by - an empty line from the rest of the commit message. It is not sufficient to - only place the text in the GitHub pull request description. + mistake), then place the text "`CLA: trivial`" on a line by itself below + the rest of your commit message separated by an empty line, like this: + + ``` + One-line summary of trivial change + + Optional main body of commit message. It might contain a sentence + or two explaining the trivial change. + + CLA: trivial + ``` + + It is not sufficient to only place the text "`CLA: trivial`" in the GitHub + pull request description. [Contributor License Agreement]: @@ -32,8 +43,8 @@ guidelines: ``` git commit --amend - [add the line, save and quit the editor] - git push -f + # add the line, save and quit the editor + git push -f [ []] ``` 2. All source files should start with the following text (with diff --git a/Configurations/windows-makefile.tmpl b/Configurations/windows-makefile.tmpl index 66550e1f82d41bb62d67ca386717b0a2335d5647..20036f5c3dd610efd418e180cd3d3046960be246 100644 --- a/Configurations/windows-makefile.tmpl +++ b/Configurations/windows-makefile.tmpl @@ -301,7 +301,7 @@ RCOUTFLAG={- $target{rcoutflag} -}$(OSSL_EMPTY) CNF_ASFLAGS={- join(' ', $target{asflags} || (), @{$config{asflags}}) -} -CNF_CPPFLAGS={- our $cppfags2 = +CNF_CPPFLAGS={- our $cppflags2 = join(' ', $target{cppflags} || (), (map { '-D'.quotify1($_) } @{$target{defines}}, @{$config{defines}}), diff --git a/NEWS.md b/NEWS.md index 07914e3fdc4ab5eed8670449f11c8f1955630dda..f85a87657c047ae897f7e70679d448da24f8c4e9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,32 +31,87 @@ OpenSSL 3.2 ### Major changes between OpenSSL 3.1 and OpenSSL 3.2 [under development] - * Added client side support for QUIC. - * Added multiple tutorials on the OpenSSL library and in particular - on writing various clients (using TLS and QUIC protocols) with libssl. - * Added support for Brainpool curves in TLS-1.3. - * Added Raw Public Key (RFC7250) support. - * Added support for certificate compression (RFC8879), including - library support for Brotli and Zstandard compression. - * Implemented support for all five instances of EdDSA from RFC8032. - * Implemented SM4-XTS support. - * Implemented deterministic ECDSA signatures (RFC6979) support. - * Implemented AES-GCM-SIV (RFC8452) support. - * Implemented Hybrid Public Key Encryption (HPKE) as defined in RFC9180. - * Multiple new features and improvements of the CMP protocol support. - * Subject or issuer names in X.509 objects are now displayed as UTF-8 strings - by default. - * TCP Fast Open (RFC7413) support is available on Linux, macOS, and FreeBSD - where enabled and supported. +OpenSSL 3.2.0 is a feature release adding significant new functionality to +OpenSSL. + +This release incorporates the following potentially significant or incompatible +changes: + * The default SSL/TLS security level has been changed from 1 to 2. - * Full support for provider-based/pluggable signature algorithms in TLS 1.3 - operations as well as CMS and X.509 data structure support. With a suitable - provider this fully enables use of post-quantum/quantum-safe cryptography. - * It is now possible to use the IANA standard names in TLS cipher - configuration. + * The `x509`, `ca`, and `req` apps now always produce X.509v3 certificates. - * Support for Argon2d, Argon2i, Argon2id KDFs has been added along with - a basic thread pool implementation for select platforms. + + * Subject or issuer names in X.509 objects are now displayed as UTF-8 strings + by default. + +This release adds the following new features: + + * Support for client side QUIC, including support for + multiple streams (RFC 9000) + + * Support for Ed25519ctx, Ed25519ph and Ed448ph in addition + to existing support for Ed25519 and Ed448 (RFC 8032) + + * Support for deterministic ECDSA signatures (RFC 6979) + + * Support for AES-GCM-SIV, a nonce-misuse-resistant AEAD (RFC 8452) + + * Support for the Argon2 KDF, along with supporting thread pool + functionality (RFC 9106) + + * Support for Hybrid Public Key Encryption (HPKE) (RFC 9180) + + * Support for SM4-XTS + + * Support for Brainpool curves in TLS 1.3 + + * Support for TLS Raw Public Keys (RFC 7250) + + * Support for TCP Fast Open on Linux, macOS and FreeBSD, + where enabled and supported (RFC 7413) + + * Support for TLS certificate compression, including library + support for zlib, Brotli and zstd (RFC 8879) + + * Support for provider-based pluggable signature algorithms + in TLS 1.3 with supporting CMS and X.509 functionality + + With a suitable provider this enables the use of post-quantum/quantum-safe + cryptography. + + * Support for using the Windows system certificate store as a source of + trusted root certificates + + This is not yet enabled by default and must be activated using an + environment variable. This is likely to become enabled by default + in a future feature release. + + * Support for using the IANA standard names in TLS ciphersuite configuration + + * Multiple new features and improvements to CMP protocol support + +The following known issues are present in this release and will be rectified +in a future release: + + * Provider-based signature algorithms cannot be configured using the + SignatureAlgorithms configuration file parameter (#22761) + +This release incorporates the following documentation enhancements: + + * Added multiple tutorials on the OpenSSL library and in particular + on writing various clients (using TLS and QUIC protocols) with libssl + + See [OpenSSL Guide]. + +A more detailed list of changes in this release can be found in the +[CHANGES.md] file. + +Users interested in using the new QUIC functionality are encouraged to read the +[README file for QUIC][README-QUIC.md], which provides links to relevant +documentation and example code. + +As always, bug reports and issues relating to OpenSSL can be [filed on our issue +tracker][issue tracker]. OpenSSL 3.1 ----------- @@ -1686,3 +1741,7 @@ OpenSSL 0.9.x [CVE-2006-2940]: https://www.openssl.org/news/vulnerabilities.html#CVE-2006-2940 [CVE-2006-2937]: https://www.openssl.org/news/vulnerabilities.html#CVE-2006-2937 [CVE-2005-2969]: https://www.openssl.org/news/vulnerabilities.html#CVE-2005-2969 +[OpenSSL Guide]: https://www.openssl.org/docs/manmaster/man7/ossl-guide-introduction.html +[CHANGES.md]: ./CHANGES.md +[README-QUIC.md]: ./README-QUIC.md +[issue tracker]: https://github.com/openssl/openssl/issues diff --git a/apps/speed.c b/apps/speed.c index 57aeb67bf89c3cd74c27635b1ef5b08563c6efa4..d1c61d72d0214f7e12361da872cb60f245b4d25a 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -310,7 +310,7 @@ enum { /* name of algorithms to test. MUST BE KEEP IN SYNC with above enum ! */ static const char *names[ALGOR_NUM] = { "md2", "mdc2", "md4", "md5", "sha1", "rmd160", - "sha256", "sha512", "whirlpool", "hmac(md5)", + "sha256", "sha512", "whirlpool", "hmac(sha256)", "des-cbc", "des-ede3", "rc4", "idea-cbc", "seed-cbc", "rc2-cbc", "rc5-cbc", "blowfish", "cast-cbc", "aes-128-cbc", "aes-192-cbc", "aes-256-cbc", @@ -570,7 +570,7 @@ static int run_benchmark(int async_jobs, int (*loop_function) (void *), static unsigned int testnum; -static char *evp_mac_mdname = "md5"; +static char *evp_mac_mdname = "sha256"; static char *evp_hmac_name = NULL; static const char *evp_md_name = NULL; static char *evp_mac_ciphername = "aes-128-cbc"; @@ -2544,7 +2544,7 @@ int speed_main(int argc, char **argv) goto end; if (!EVP_MAC_CTX_set_params(loopargs[i].mctx, params)) - goto skip_hmac; /* Digest not found */ + goto end; /* Digest not found */ } for (testnum = 0; testnum < size_num; testnum++) { print_message(names[D_HMAC], lengths[testnum], seconds.sym); @@ -2560,7 +2560,7 @@ int speed_main(int argc, char **argv) EVP_MAC_free(mac); mac = NULL; } -skip_hmac: + if (doit[D_CBC_DES]) { int st = 1; diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index 65f9674037761729e232d3e83f4864533b033863..99a72f4dffe3cf492f7b6885c9e690f3117cd1b4 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -560,7 +560,7 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, { CMS_SignerInfo *rct_si; CMS_ContentInfo *cms = NULL; - ASN1_OCTET_STRING **pos, *os; + ASN1_OCTET_STRING **pos, *os = NULL; BIO *rct_cont = NULL; int r = 0; const CMS_CTX *ctx = si->cms_ctx; @@ -622,6 +622,7 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si, if (r) return cms; CMS_ContentInfo_free(cms); + ASN1_OCTET_STRING_free(os); return NULL; } diff --git a/crypto/pkcs7/pk7_attr.c b/crypto/pkcs7/pk7_attr.c index 68f0a5c29078d0ba36b1bec57fc3a3e65730abb3..a12d65bb8e31f844b596c2137fe598660f31a1de 100644 --- a/crypto/pkcs7/pk7_attr.c +++ b/crypto/pkcs7/pk7_attr.c @@ -28,8 +28,12 @@ int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si, } seq->length = ASN1_item_i2d((ASN1_VALUE *)cap, &seq->data, ASN1_ITEM_rptr(X509_ALGORS)); - return PKCS7_add_signed_attribute(si, NID_SMIMECapabilities, - V_ASN1_SEQUENCE, seq); + if (!PKCS7_add_signed_attribute(si, NID_SMIMECapabilities, + V_ASN1_SEQUENCE, seq)) { + ASN1_STRING_free(seq); + return 0; + } + return 1; } STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si) @@ -98,12 +102,18 @@ int PKCS7_add_attrib_content_type(PKCS7_SIGNER_INFO *si, ASN1_OBJECT *coid) int PKCS7_add0_attrib_signing_time(PKCS7_SIGNER_INFO *si, ASN1_TIME *t) { - if (t == NULL && (t = X509_gmtime_adj(NULL, 0)) == NULL) { + ASN1_TIME *tmp = NULL; + + if (t == NULL && (tmp = t = X509_gmtime_adj(NULL, 0)) == NULL) { ERR_raise(ERR_LIB_PKCS7, ERR_R_X509_LIB); return 0; } - return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, - V_ASN1_UTCTIME, t); + if (!PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, + V_ASN1_UTCTIME, t)) { + ASN1_TIME_free(tmp); + return 0; + } + return 1; } int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si, diff --git a/crypto/sha/asm/keccak1600-armv4.pl b/crypto/sha/asm/keccak1600-armv4.pl index f19076c248c1b64c644d9b0648e52db7ddeb492e..f9a8cd1f0046af27ce963be51c6514d3c279eaa5 100755 --- a/crypto/sha/asm/keccak1600-armv4.pl +++ b/crypto/sha/asm/keccak1600-armv4.pl @@ -933,7 +933,7 @@ SHA3_absorb: ___ } -{ my ($out,$len,$A_flat,$bsz,$next) = map("r$_", (4,5,10,12,11)); +{ my ($out,$len,$A_flat,$bsz,$next) = map("r$_", (4,5,10,12,0)); # void SHA3_squeeze(uint64_t A[5][5], @@ -947,13 +947,13 @@ $code.=<<___; .type SHA3_squeeze,%function .align 5 SHA3_squeeze: - stmdb sp!,{r0,r3-r11,lr} @ push 11 registers + stmdb sp!,{r0,r3-r10,lr} mov $A_flat,r0 mov $out,r1 mov $len,r2 mov $bsz,r3 - ldr $next, [sp, #48] @ next is after the 11 pushed registers (12*4) + ldr $next, [sp, #40] @ next is after the 10 pushed registers (10*4) #ifdef __thumb2__ mov r9,#0x00ff00ff @@ -1090,9 +1090,9 @@ SHA3_squeeze: .Lsqueeze_done: add sp,sp,#24 #if __ARM_ARCH__>=5 - ldmia sp!,{r4-r11,pc} + ldmia sp!,{r4-r10,pc} #else - ldmia sp!,{r4-r11,lr} + ldmia sp!,{r4-r10,lr} tst lr,#1 moveq pc,lr @ be binary compatible with V4, yet bx lr @ interoperable with Thumb ISA:-) diff --git a/crypto/sha/asm/keccak1600-armv8.pl b/crypto/sha/asm/keccak1600-armv8.pl index 72f8c3adb577bfa70ecf5f329fd8708f5efcac3a..7566a7e3ece1d55fa23d6579b2d60e05536f19b3 100755 --- a/crypto/sha/asm/keccak1600-armv8.pl +++ b/crypto/sha/asm/keccak1600-armv8.pl @@ -483,7 +483,7 @@ SHA3_squeeze: mov $out,x1 mov $len,x2 mov $bsz,x3 - cmp x4, #0 // x4 = 'next' argument + cmp w4, #0 // w4 = 'next' argument bne .Lnext_block .Loop_squeeze: diff --git a/crypto/sha/asm/keccak1600-ppc64.pl b/crypto/sha/asm/keccak1600-ppc64.pl index fe7d6db20e43d26f49dbb39d16de35c361640c01..54f32e8c9291503bbbcb2427e93d0d0311b2f23c 100755 --- a/crypto/sha/asm/keccak1600-ppc64.pl +++ b/crypto/sha/asm/keccak1600-ppc64.pl @@ -668,7 +668,7 @@ SHA3_squeeze: subi $out,r4,1 ; prepare for stbu mr $len,r5 mr $bsz,r6 - ${UCMP}i r7,0 ; r7 = 'next' argument + cmplwi r7,0 ; r7 = 'next' argument bne .Lnext_block b .Loop_squeeze diff --git a/crypto/sha/asm/keccak1600-x86_64.pl b/crypto/sha/asm/keccak1600-x86_64.pl index bddcaf8294192ba927af37c5e1bd3339f451f68a..78aa5c64aff0e9f95de92cc60c047caf0fd3dcf7 100755 --- a/crypto/sha/asm/keccak1600-x86_64.pl +++ b/crypto/sha/asm/keccak1600-x86_64.pl @@ -524,7 +524,7 @@ SHA3_squeeze: mov %rsi,$out mov %rdx,$len mov %rcx,$bsz - bt \$0,$next + bt \$0,${next}d jc .Lnext_block jmp .Loop_squeeze diff --git a/crypto/sha/build.info b/crypto/sha/build.info index 92f48531ceb10ea8b0331316d675e98b1a963aa2..95767e9589b11334d62c5ed1e8be6f54048f6c9e 100644 --- a/crypto/sha/build.info +++ b/crypto/sha/build.info @@ -169,15 +169,16 @@ GENERATE[keccak1600-s390x.S]=asm/keccak1600-s390x.pl GENERATE[sha1-c64xplus.S]=asm/sha1-c64xplus.pl GENERATE[sha256-c64xplus.S]=asm/sha256-c64xplus.pl GENERATE[sha512-c64xplus.S]=asm/sha512-c64xplus.pl -GENERATE[keccak1600-c64x.S]=asm/keccak1600-c64x.pl GENERATE[sha256-riscv64-zvkb-zvknha_or_zvknhb.S]=asm/sha256-riscv64-zvkb-zvknha_or_zvknhb.pl GENERATE[sha512-riscv64-zvkb-zvknhb.S]=asm/sha512-riscv64-zvkb-zvknhb.pl -# These are not yet used +# These are not yet used and do not support multi-squeeze +GENERATE[keccak1600-c64x.S]=asm/keccak1600-c64x.pl GENERATE[keccak1600-avx2.S]=asm/keccak1600-avx2.pl GENERATE[keccak1600-avx512.S]=asm/keccak1600-avx512.pl GENERATE[keccak1600-avx512vl.S]=asm/keccak1600-avx512vl.pl GENERATE[keccak1600-mmx.S]=asm/keccak1600-mmx.pl GENERATE[keccak1600p8-ppc.S]=asm/keccak1600p8-ppc.pl + GENERATE[sha1-thumb.S]=asm/sha1-thumb.pl diff --git a/demos/guide/quic-client-block.c b/demos/guide/quic-client-block.c index 782f57155937a47821158f20c07308ca8cd28c89..baf5292c477992bf81ff719aa9d8a8f95e2dac02 100644 --- a/demos/guide/quic-client-block.c +++ b/demos/guide/quic-client-block.c @@ -27,7 +27,7 @@ /* Helper function to create a BIO connected to the server */ static BIO *create_socket_bio(const char *hostname, const char *port, - BIO_ADDR **peer_addr) + int family, BIO_ADDR **peer_addr) { int sock = -1; BIO_ADDRINFO *res; @@ -37,7 +37,7 @@ static BIO *create_socket_bio(const char *hostname, const char *port, /* * Lookup IP address info for the server. */ - if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_DGRAM, 0, + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_DGRAM, 0, &res)) return NULL; @@ -128,14 +128,24 @@ int main(int argc, char *argv[]) char buf[160]; BIO_ADDR *peer_addr = NULL; char *hostname, *port; + int argnext = 1; + int ipv6 = 0; - if (argc != 3) { - printf("Usage: quic-client-block hostname port\n"); + if (argc < 3) { + printf("Usage: quic-client-block [-6] hostname port\n"); goto end; } - hostname = argv[1]; - port = argv[2]; + if (!strcmp(argv[argnext], "-6")) { + if (argc < 4) { + printf("Usage: quic-client-block [-6] hostname port\n"); + goto end; + } + ipv6 = 1; + argnext++; + } + hostname = argv[argnext++]; + port = argv[argnext]; /* * Create an SSL_CTX which we can use to create SSL objects from. We @@ -172,7 +182,7 @@ int main(int argc, char *argv[]) * Create the underlying transport socket/BIO and associate it with the * connection. */ - bio = create_socket_bio(hostname, port, &peer_addr); + bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET, &peer_addr); if (bio == NULL) { printf("Failed to crete the BIO\n"); goto end; diff --git a/demos/guide/quic-client-non-block.c b/demos/guide/quic-client-non-block.c index 31596d84c570e7e082177db4f2d34c56563ac8d4..a6c1802fcd68abe3b58d5f345f73264a6aec6bb4 100644 --- a/demos/guide/quic-client-non-block.c +++ b/demos/guide/quic-client-non-block.c @@ -28,7 +28,7 @@ /* Helper function to create a BIO connected to the server */ static BIO *create_socket_bio(const char *hostname, const char *port, - BIO_ADDR **peer_addr) + int family, BIO_ADDR **peer_addr) { int sock = -1; BIO_ADDRINFO *res; @@ -38,7 +38,7 @@ static BIO *create_socket_bio(const char *hostname, const char *port, /* * Lookup IP address info for the server. */ - if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_DGRAM, 0, + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_DGRAM, 0, &res)) return NULL; @@ -236,14 +236,24 @@ int main(int argc, char *argv[]) BIO_ADDR *peer_addr = NULL; int eof = 0; char *hostname, *port; + int ipv6 = 0; + int argnext = 1; - if (argc != 3) { - printf("Usage: quic-client-non-block hostname port\n"); + if (argc < 3) { + printf("Usage: quic-client-non-block [-6] hostname port\n"); goto end; } - hostname = argv[1]; - port = argv[2]; + if (!strcmp(argv[argnext], "-6")) { + if (argc < 4) { + printf("Usage: quic-client-non-block [-6] hostname port\n"); + goto end; + } + ipv6 = 1; + argnext++; + } + hostname = argv[argnext++]; + port = argv[argnext]; /* * Create an SSL_CTX which we can use to create SSL objects from. We @@ -280,7 +290,8 @@ int main(int argc, char *argv[]) * Create the underlying transport socket/BIO and associate it with the * connection. */ - bio = create_socket_bio(hostname, port, &peer_addr); + bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET, + &peer_addr); if (bio == NULL) { printf("Failed to crete the BIO\n"); goto end; diff --git a/demos/guide/quic-multi-stream.c b/demos/guide/quic-multi-stream.c index 469c5ba4b282efa39181b7d7addbcafd9e86d9c1..d31ea245c8015dc175f16d7be753a5524bfd058a 100644 --- a/demos/guide/quic-multi-stream.c +++ b/demos/guide/quic-multi-stream.c @@ -27,7 +27,7 @@ /* Helper function to create a BIO connected to the server */ static BIO *create_socket_bio(const char *hostname, const char *port, - BIO_ADDR **peer_addr) + int family, BIO_ADDR **peer_addr) { int sock = -1; BIO_ADDRINFO *res; @@ -37,7 +37,7 @@ static BIO *create_socket_bio(const char *hostname, const char *port, /* * Lookup IP address info for the server. */ - if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_DGRAM, 0, + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_DGRAM, 0, &res)) return NULL; @@ -148,14 +148,24 @@ int main(int argc, char *argv[]) char buf[160]; BIO_ADDR *peer_addr = NULL; char *hostname, *port; + int argnext = 1; + int ipv6 = 0; - if (argc != 3) { - printf("Usage: quic-client-non-block hostname port\n"); + if (argc < 3) { + printf("Usage: quic-client-non-block [-6] hostname port\n"); goto end; } - hostname = argv[1]; - port = argv[2]; + if (!strcmp(argv[argnext], "-6")) { + if (argc < 4) { + printf("Usage: quic-client-non-block [-6] hostname port\n"); + goto end; + } + ipv6 = 1; + argnext++; + } + hostname = argv[argnext++]; + port = argv[argnext]; /* * Create an SSL_CTX which we can use to create SSL objects from. We @@ -201,7 +211,7 @@ int main(int argc, char *argv[]) * Create the underlying transport socket/BIO and associate it with the * connection. */ - bio = create_socket_bio(hostname, port, &peer_addr); + bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET, &peer_addr); if (bio == NULL) { printf("Failed to crete the BIO\n"); goto end; diff --git a/demos/guide/tls-client-block.c b/demos/guide/tls-client-block.c index ea7d68467ac6ccaebd59b9221094df4077372f9d..c6ba5850f7ff983310fe139b5b6403c4497bdeaa 100644 --- a/demos/guide/tls-client-block.c +++ b/demos/guide/tls-client-block.c @@ -26,7 +26,7 @@ #include /* Helper function to create a BIO connected to the server */ -static BIO *create_socket_bio(const char *hostname, const char *port) +static BIO *create_socket_bio(const char *hostname, const char *port, int family) { int sock = -1; BIO_ADDRINFO *res; @@ -36,7 +36,7 @@ static BIO *create_socket_bio(const char *hostname, const char *port) /* * Lookup IP address info for the server. */ - if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_STREAM, 0, + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_STREAM, 0, &res)) return NULL; @@ -109,14 +109,24 @@ int main(int argc, char *argv[]) size_t written, readbytes; char buf[160]; char *hostname, *port; + int argnext = 1; + int ipv6 = 0; - if (argc != 3) { - printf("Usage: tls-client-block hostname port\n"); + if (argc < 3) { + printf("Usage: tls-client-block [-6] hostname port\n"); goto end; } - hostname = argv[1]; - port = argv[2]; + if (!strcmp(argv[argnext], "-6")) { + if (argc < 4) { + printf("Usage: tls-client-block [-6] hostname port\n"); + goto end; + } + ipv6 = 1; + argnext++; + } + hostname = argv[argnext++]; + port = argv[argnext]; /* * Create an SSL_CTX which we can use to create SSL objects from. We @@ -162,7 +172,7 @@ int main(int argc, char *argv[]) * Create the underlying transport socket/BIO and associate it with the * connection. */ - bio = create_socket_bio(hostname, port); + bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET); if (bio == NULL) { printf("Failed to crete the BIO\n"); goto end; diff --git a/demos/guide/tls-client-non-block.c b/demos/guide/tls-client-non-block.c index 8748e4fffc772e904b0d4b54e62af8f5b7a00c13..0b19d67762674e192fee28a6621b9b37233620cf 100644 --- a/demos/guide/tls-client-non-block.c +++ b/demos/guide/tls-client-non-block.c @@ -27,7 +27,7 @@ #include /* Helper function to create a BIO connected to the server */ -static BIO *create_socket_bio(const char *hostname, const char *port) +static BIO *create_socket_bio(const char *hostname, const char *port, int family) { int sock = -1; BIO_ADDRINFO *res; @@ -37,7 +37,7 @@ static BIO *create_socket_bio(const char *hostname, const char *port) /* * Lookup IP address info for the server. */ - if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_STREAM, 0, + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_STREAM, 0, &res)) return NULL; @@ -187,14 +187,25 @@ int main(int argc, char *argv[]) char buf[160]; int eof = 0; char *hostname, *port; + int argnext = 1; + int ipv6 = 0; - if (argc != 3) { - printf("Usage: tls-client-non-block hostname port\n"); + if (argc < 3) { + printf("Usage: tls-client-non-block [-6] hostname port\n"); goto end; } - hostname = argv[1]; - port = argv[2]; + if (!strcmp(argv[argnext], "-6")) { + if (argc < 4) { + printf("Usage: tls-client-non-block [-6] hostname port\n"); + goto end; + } + ipv6 = 1; + argnext++; + } + + hostname = argv[argnext++]; + port = argv[argnext]; /* * Create an SSL_CTX which we can use to create SSL objects from. We @@ -240,7 +251,7 @@ int main(int argc, char *argv[]) * Create the underlying transport socket/BIO and associate it with the * connection. */ - bio = create_socket_bio(hostname, port); + bio = create_socket_bio(hostname, port, ipv6 ? AF_INET6 : AF_INET); if (bio == NULL) { printf("Failed to crete the BIO\n"); goto end; diff --git a/doc/designs/quic-design/glossary.md b/doc/designs/quic-design/glossary.md index 1f947ef37d417b530601819cf0ab0b51910b9bf7..fdaa822196712082cdc90db9157e1a0b4de68d0a 100644 --- a/doc/designs/quic-design/glossary.md +++ b/doc/designs/quic-design/glossary.md @@ -201,6 +201,11 @@ forming. This is the CMPPL minus any bytes we have already put into the payload. **SCID:** Source Connection ID. Found in some QUIC packet headers. +**SRT:** Stateless reset token. + +**SRTM:** Stateless reset token manager. Object which tracks SRTs we have +received. + **SSTREAM:** Send stream. Internal send buffer management object used to store data which has been passed to libssl for sending but which has not yet been transmitted, or not yet been acknowledged. diff --git a/doc/images/openssl-square-nontransparent.png b/doc/images/openssl-square-nontransparent.png new file mode 100644 index 0000000000000000000000000000000000000000..5e6b747ce0879921715ad64523a2d055be27f075 Binary files /dev/null and b/doc/images/openssl-square-nontransparent.png differ diff --git a/doc/images/openssl-square.svg b/doc/images/openssl-square.svg new file mode 100644 index 0000000000000000000000000000000000000000..bb1ddc0490f30036908b5fae868e97958998b225 --- /dev/null +++ b/doc/images/openssl-square.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/images/openssl.svg b/doc/images/openssl.svg index 9cd6794fbdcfaf07528494af55acce6898fe7f3d..988d3a0e91bedc31a5aad615b4001b5db3a4baa7 100644 --- a/doc/images/openssl.svg +++ b/doc/images/openssl.svg @@ -1,41 +1,49 @@ - - - - - OpenSSL - Cryptography and SSL/TLS Toolkit - + + + + + + + + + + + + + + + + + + + diff --git a/doc/man7/EVP_MAC-BLAKE2.pod b/doc/man7/EVP_MAC-BLAKE2.pod index 5557e153536a08d1ac8008950be319b144979c5f..f1106ef5a2d1956b692285c4db70791c74b093dd 100644 --- a/doc/man7/EVP_MAC-BLAKE2.pod +++ b/doc/man7/EVP_MAC-BLAKE2.pod @@ -27,7 +27,8 @@ properties, to be used with EVP_MAC_fetch(): The general description of these parameters can be found in L. -All these parameters can be set with EVP_MAC_CTX_set_params(). +All these parameters (except for "block-size") can be set with +EVP_MAC_CTX_set_params(). Furthermore, the "size" parameter can be retrieved with EVP_MAC_CTX_get_params(), or with EVP_MAC_CTX_get_mac_size(). The length of the "size" parameter should not exceed that of a B. @@ -45,7 +46,7 @@ Setting this parameter is identical to passing a I to L. =item "custom" (B) -Sets the custom value. +Sets the customization/personalization string. It is an optional value of at most 16 bytes for BLAKE2BMAC or 8 for BLAKE2SMAC, and is empty by default. @@ -62,10 +63,10 @@ It can be any number between 1 and 32 for EVP_MAC_BLAKE2S or between 1 and 64 for EVP_MAC_BLAKE2B. It is 32 and 64 respectively by default. -=item "block-size" (B) +=item "block-size" (B) Gets the MAC block size. -By default, it is 64 for EVP_MAC_BLAKE2S and 128 for EVP_MAC_BLAKE2B. +It is 64 for EVP_MAC_BLAKE2S and 128 for EVP_MAC_BLAKE2B. =back diff --git a/doc/man7/EVP_MAC-CMAC.pod b/doc/man7/EVP_MAC-CMAC.pod index 3fb530c4cfe166b2ac975293a68f3149a05c4c85..44c5fc7c44e18f45f3731bbc910fa9aa5a3a5269 100644 --- a/doc/man7/EVP_MAC-CMAC.pod +++ b/doc/man7/EVP_MAC-CMAC.pod @@ -63,7 +63,7 @@ The length of the "size" parameter is equal to that of an B. =over 4 -=item "block-size" (B) +=item "block-size" (B) Gets the MAC block size. The "block-size" parameter can also be retrieved with EVP_MAC_CTX_get_block_size(). diff --git a/doc/man7/EVP_MAC-HMAC.pod b/doc/man7/EVP_MAC-HMAC.pod index ea2eda9ec81902c298b561362a03ac7c9d7a368e..0e401710fc92300732d7a7a4fa5eb55f7d8f3880 100644 --- a/doc/man7/EVP_MAC-HMAC.pod +++ b/doc/man7/EVP_MAC-HMAC.pod @@ -76,7 +76,7 @@ The length of the "size" parameter is equal to that of an B. =over 4 -=item "block-size" (B) +=item "block-size" (B) Gets the MAC block size. The "block-size" parameter can also be retrieved with EVP_MAC_CTX_get_block_size(). diff --git a/doc/man7/EVP_MAC-KMAC.pod b/doc/man7/EVP_MAC-KMAC.pod index dc67c66336df45dba520e8b6757adccf479cd027..9c4fbc0b2ad9c9116f8f005d2500f84e89d0d5ec 100644 --- a/doc/man7/EVP_MAC-KMAC.pod +++ b/doc/man7/EVP_MAC-KMAC.pod @@ -27,7 +27,8 @@ properties, to be used with EVP_MAC_fetch(): The general description of these parameters can be found in L. -All these parameters can be set with EVP_MAC_CTX_set_params(). +All these parameters (except for "block-size") can be set with +EVP_MAC_CTX_set_params(). Furthermore, the "size" parameter can be retrieved with EVP_MAC_CTX_get_params(), or with EVP_MAC_CTX_get_mac_size(). The length of the "size" parameter should not exceed that of a B. @@ -45,18 +46,19 @@ The length of the key (in bytes) must be in the range 4...512. =item "custom" (B) -Sets the custom value. -It is an optional value with a length of at most 512 bytes, and is empty by default. +Sets the customization string. +It is an optional value with a length of at most 512 bytes, and is +empty by default. =item "size" (B) Sets the MAC size. By default, it is 32 for C and 64 for C. -=item "block-size" (B) +=item "block-size" (B) Gets the MAC block size. -By default, it is 168 for C and 136 for C. +It is 168 for C and 136 for C. =item "xof" (B) diff --git a/doc/man7/EVP_MD-SHAKE.pod b/doc/man7/EVP_MD-SHAKE.pod index 6f1fe9cae64f7a320a0f2062957ba8f502cf48ae..e0395f887b4401d5ef840768afa157059d736e4d 100644 --- a/doc/man7/EVP_MD-SHAKE.pod +++ b/doc/man7/EVP_MD-SHAKE.pod @@ -10,8 +10,9 @@ EVP_MD-SHAKE, EVP_MD-KECCAK-KMAC Support for computing SHAKE or KECCAK-KMAC digests through the B API. -KECCAK-KMAC is a special digest that's used by the KMAC EVP_MAC -implementation (see L). +KECCAK-KMAC is an Extendable Output Function (XOF), with a definition +similar to SHAKE, used by the KMAC EVP_MAC implementation (see +L). =head2 Identities @@ -22,21 +23,25 @@ provider, and includes the following varieties: =item KECCAK-KMAC-128 -Known names are "KECCAK-KMAC-128" and "KECCAK-KMAC128" -This is used by L +Known names are "KECCAK-KMAC-128" and "KECCAK-KMAC128". This is used +by L. Using the notation from NIST FIPS 202 +(Section 6.2), we have KECCAK-KMAC-128(M, d) = KECCAK[256](M || 00, d) +(see the description of KMAC128 in Appendix A of NIST SP 800-185). =item KECCAK-KMAC-256 -Known names are "KECCAK-KMAC-256" and "KECCAK-KMAC256" -This is used by L +Known names are "KECCAK-KMAC-256" and "KECCAK-KMAC256". This is used +by L. Using the notation from NIST FIPS 202 +(Section 6.2), we have KECCAK-KMAC-256(M, d) = KECCAK[512](M || 00, d) +(see the description of KMAC256 in Appendix A of NIST SP 800-185). =item SHAKE-128 -Known names are "SHAKE-128" and "SHAKE128" +Known names are "SHAKE-128" and "SHAKE128". =item SHAKE-256 -Known names are "SHAKE-256" and "SHAKE256" +Known names are "SHAKE-256" and "SHAKE256". =back diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod index 449d5624e004a2fde878babdcb08974fc41b87e1..485c4c63416e89402d9fb7dc208c60801ce95ef9 100644 --- a/doc/man7/OSSL_PROVIDER-FIPS.pod +++ b/doc/man7/OSSL_PROVIDER-FIPS.pod @@ -72,6 +72,8 @@ The OpenSSL FIPS provider supports these operations and algorithms: =item KECCAK-KMAC, see L +=item SHAKE, see L + =back =head2 Symmetric Ciphers @@ -80,6 +82,10 @@ The OpenSSL FIPS provider supports these operations and algorithms: =item AES, see L +=item 3DES, see L + +This is an unapproved algorithm. + =back =head2 Message Authentication Code (MAC) @@ -134,6 +140,10 @@ The OpenSSL FIPS provider supports these operations and algorithms: =item X448, see L +=item TLS1-PRF + +=item HKDF + =back =head2 Asymmetric Signature @@ -142,9 +152,17 @@ The OpenSSL FIPS provider supports these operations and algorithms: =item RSA, see L -=item X25519, see L +=item DSA, see L + +=item ED25519, see L + +This is an unapproved algorithm. + +=item ED448, see L + +This is an unapproved algorithm. -=item X448, see L +=item ECDSA, see L =item HMAC, see L @@ -180,12 +198,30 @@ The OpenSSL FIPS provider supports these operations and algorithms: =item RSA, see L +=item RSA-PSS + =item EC, see L =item X25519, see L =item X448, see L +=item ED25519, see L + +This is an unapproved algorithm. + +=item ED448, see L + +This is an unapproved algorithm. + +=item TLS1-PRF + +=item HKDF + +=item HMAC, see L + +=item CMAC, see L + =back =head2 Random Number Generation diff --git a/doc/man7/OSSL_PROVIDER-base.pod b/doc/man7/OSSL_PROVIDER-base.pod index c51adbde1e97def5541d9459cd45fd791161b9ca..24d610f28c2b2d3b480c7d0af719cbbd9a3b2b3a 100644 --- a/doc/man7/OSSL_PROVIDER-base.pod +++ b/doc/man7/OSSL_PROVIDER-base.pod @@ -57,28 +57,96 @@ currently permitted. The OpenSSL base provider supports these operations and algorithms: +=head2 Random Number Generation + +=over 4 + +=item SEED-SRC, see L + +=back + +In addition to this provider, the "SEED-SRC" algorithm is also available in the +default provider. + =head2 Asymmetric Key Encoder -In addition to "provider=base", some of these encoders define the -property "fips=yes", to allow them to be used together with the FIPS -provider. +=over 4 + +=item RSA + +=item RSA-PSS + +=item DH + +=item DHX + +=item DSA + +=item EC + +=item ED25519 + +=item ED448 + +=item X25519 + +=item X448 + +=item SM2 + +=back + +In addition to this provider, all of these encoding algorithms are also +available in the default provider. Some of these algorithms may be used in +combination with the FIPS provider. + +=head2 Asymmetric Key Decoder =over 4 -=item RSA, see L +=item RSA + +=item RSA-PSS + +=item DH + +=item DHX + +=item DSA + +=item EC + +=item ED25519 -=item DH, see L +=item ED448 -=item DSA, see L +=item X25519 -=item EC, see L +=item X448 -=item X25519, see L +=item SM2 -=item X448, see L +=item DER =back +In addition to this provider, all of these decoding algorithms are also +available in the default provider. Some of these algorithms may be used in +combination with the FIPS provider. + +=head2 Stores + +=over 4 + +=item file + +=item org.openssl.winstore + +=back + +In addition to this provider, all of these store algorithms are also +available in the default provider. + =head1 SEE ALSO L, L, diff --git a/doc/man7/OSSL_PROVIDER-default.pod b/doc/man7/OSSL_PROVIDER-default.pod index 603fd06331bbfb4dbc65b8280eee7c1d2a45de3b..feba00aa7638a02e0623623743be233ce34886f2 100644 --- a/doc/man7/OSSL_PROVIDER-default.pod +++ b/doc/man7/OSSL_PROVIDER-default.pod @@ -89,8 +89,6 @@ The OpenSSL default provider supports these operations and algorithms: =item 3DES, see L -=item SEED, see L - =item SM4, see L =item ChaCha20, see L @@ -127,6 +125,8 @@ The OpenSSL default provider supports these operations and algorithms: =item HKDF, see L +=item TLS13-KDF, see L + =item SSKDF, see L =item PBKDF2, see L @@ -167,6 +167,12 @@ The OpenSSL default provider supports these operations and algorithms: =item X448, see L +=item TLS1-PRF + +=item HKDF + +=item SCRYPT + =back =head2 Asymmetric Signature @@ -177,6 +183,14 @@ The OpenSSL default provider supports these operations and algorithms: =item RSA, see L +=item ED25519, see L + +=item ED448, see L + +=item ECDSA, see L + +=item SM2 + =item HMAC, see L =item SIPHASH, see L @@ -205,6 +219,8 @@ The OpenSSL default provider supports these operations and algorithms: =item X25519, see L +=item X448, see L + =item EC, see L =back @@ -221,12 +237,34 @@ The OpenSSL default provider supports these operations and algorithms: =item RSA, see L +=item RSA-PSS + =item EC, see L =item X25519, see L =item X448, see L +=item ED25519, see L + +=item ED448, see L + +=item TLS1-PRF + +=item HKDF + +=item SCRYPT + +=item HMAC, see L + +=item SIPHASH, see L + +=item POLY1305, see L + +=item CMAC, see L + +=item SM2, see L + =back =head2 Random Number Generation @@ -245,28 +283,88 @@ The OpenSSL default provider supports these operations and algorithms: =back +In addition to this provider, the "SEED-SRC" algorithm is also available in the +base provider. + =head2 Asymmetric Key Encoder -The default provider also includes all of the encoding algorithms -present in the base provider. Some of these have the property "fips=yes", -to allow them to be used together with the FIPS provider. +=over 4 + +=item RSA + +=item RSA-PSS + +=item DH + +=item DHX + +=item DSA + +=item EC + +=item ED25519 + +=item ED448 + +=item X25519 + +=item X448 + +=item SM2 + +=back + +In addition to this provider, all of these encoding algorithms are also +available in the base provider. Some of these algorithms may be used in +combination with the FIPS provider. + +=head2 Asymmetric Key Decoder =over 4 -=item RSA, see L +=item RSA + +=item RSA-PSS + +=item DH -=item DH, see L +=item DHX -=item DSA, see L +=item DSA -=item EC, see L +=item EC -=item X25519, see L +=item ED25519 -=item X448, see L +=item ED448 + +=item X25519 + +=item X448 + +=item SM2 + +=item DER =back +In addition to this provider, all of these decoding algorithms are also +available in the base provider. Some of these algorithms may be used in +combination with the FIPS provider. + +=head2 Stores + +=over 4 + +=item file + +=item org.openssl.winstore + +=back + +In addition to this provider, all of these store algorithms are also +available in the base provider. + =head1 SEE ALSO L, L, L, diff --git a/doc/man7/OSSL_PROVIDER-legacy.pod b/doc/man7/OSSL_PROVIDER-legacy.pod index 82781a09b2e91ec0501a88c97218d6a990abcb7f..d70de3682f34e6c5f8c24e09fb0a1f300a5108c5 100644 --- a/doc/man7/OSSL_PROVIDER-legacy.pod +++ b/doc/man7/OSSL_PROVIDER-legacy.pod @@ -42,6 +42,8 @@ The OpenSSL legacy provider supports these operations and algorithms: =item MD2, see L +Disabled by default. Use I config option to enable. + =item MD4, see L =item MDC2, see L diff --git a/doc/man7/ossl-guide-quic-client-block.pod b/doc/man7/ossl-guide-quic-client-block.pod index fc8912086dae6419dd10f53aa14bc0d2218bf197..ab018e4a220b8500d72dc67adb78a3c912060570 100644 --- a/doc/man7/ossl-guide-quic-client-block.pod +++ b/doc/man7/ossl-guide-quic-client-block.pod @@ -94,7 +94,7 @@ for TCP). /* * Lookup IP address info for the server. */ - if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_DGRAM, 0, + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_DGRAM, 0, &res)) return NULL; diff --git a/doc/man7/ossl-guide-tls-client-block.pod b/doc/man7/ossl-guide-tls-client-block.pod index cb67bf8fa9bd413608ec6a52822b4219f1c47549..ba59bd4ab3c8131b11e5c86a0071ad76dbd292a2 100644 --- a/doc/man7/ossl-guide-tls-client-block.pod +++ b/doc/man7/ossl-guide-tls-client-block.pod @@ -174,7 +174,7 @@ integrate into the OpenSSL error system to log error data, e.g. /* * Lookup IP address info for the server. */ - if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, 0, SOCK_STREAM, 0, + if (!BIO_lookup_ex(hostname, port, BIO_LOOKUP_CLIENT, family, SOCK_STREAM, 0, &res)) return NULL; @@ -212,7 +212,9 @@ See L, L, L, L, L, L and L for further information on the functions used here. In the above example code the B and B variables are strings, e.g. -"www.example.com" and "443". +"www.example.com" and "443". Note also the use of the family variable, which +can take the values of AF_INET or AF_INET6 based on the command line -6 option, +to allow specific connections to an ipv4 or ipv6 enabled host. Sockets created using the methods described above will automatically be blocking sockets - which is exactly what we want for this example. diff --git a/fuzz/build.info b/fuzz/build.info index de7cadc79e535f2c3957c283c42f94eb91d79e83..bbbc7c9654a8e5047f81afd4cd49acb370eddf8f 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -30,7 +30,7 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] ENDIF IF[{- !$disabled{"quic"} -}] - PROGRAMS{noinst}=quic-client + PROGRAMS{noinst}=quic-client quic-srtm ENDIF SOURCE[asn1]=asn1.c driver.c fuzz_rand.c @@ -97,6 +97,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] INCLUDE[quic-client]=../include {- $ex_inc -} DEPEND[quic-client]=../libcrypto.a ../libssl.a {- $ex_lib -} + SOURCE[quic-srtm]=quic-srtm.c driver.c fuzz_rand.c + INCLUDE[quic-srtm]=../include {- $ex_inc -} + DEPEND[quic-srtm]=../libcrypto.a ../libssl.a {- $ex_lib -} + SOURCE[server]=server.c driver.c fuzz_rand.c INCLUDE[server]=../include {- $ex_inc -} DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} @@ -128,7 +132,7 @@ IF[{- !$disabled{tests} -}] ENDIF IF[{- !$disabled{"quic"} -}] - PROGRAMS{noinst}=quic-client-test + PROGRAMS{noinst}=quic-client-test quic-srtm-test ENDIF SOURCE[asn1-test]=asn1.c test-corpus.c fuzz_rand.c @@ -196,6 +200,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[quic-client-test]=../include DEPEND[quic-client-test]=../libcrypto.a ../libssl.a + SOURCE[quic-srtm-test]=quic-srtm.c test-corpus.c fuzz_rand.c + INCLUDE[quic-srtm-test]=../include + DEPEND[quic-srtm-test]=../libcrypto.a ../libssl.a + SOURCE[server-test]=server.c test-corpus.c fuzz_rand.c INCLUDE[server-test]=../include DEPEND[server-test]=../libcrypto ../libssl diff --git a/fuzz/corpora b/fuzz/corpora index d600d8ed1b286040019b3c1ece629b5b174eb444..8663e2d71fa934e7846fa4c5fb6de7cb3afc53fd 160000 --- a/fuzz/corpora +++ b/fuzz/corpora @@ -1 +1 @@ -Subproject commit d600d8ed1b286040019b3c1ece629b5b174eb444 +Subproject commit 8663e2d71fa934e7846fa4c5fb6de7cb3afc53fd diff --git a/fuzz/helper.py b/fuzz/helper.py index 9185b17228bb0d091e50091d1d4eb3247f11f95c..db6e8edc1e5d78c3b1a9ed82c78a844f0aa3a704 100755 --- a/fuzz/helper.py +++ b/fuzz/helper.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. # diff --git a/fuzz/quic-srtm.c b/fuzz/quic-srtm.c new file mode 100644 index 0000000000000000000000000000000000000000..eb676c227981b980cbc28c0ffe1f98117b217d4b --- /dev/null +++ b/fuzz/quic-srtm.c @@ -0,0 +1,119 @@ +/* + * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.openssl.org/source/license.html + * or in the file LICENSE in the source distribution. + */ + +#include +#include +#include +#include "fuzzer.h" +#include "internal/quic_srtm.h" + +int FuzzerInitialize(int *argc, char ***argv) +{ + FuzzerSetRand(); + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL); + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + ERR_clear_error(); + return 1; +} + +/* + * Fuzzer input "protocol": + * Big endian + * Zero or more of: + * ADD - u8(0x00) u64(opaque) u64(seq_num) u128(token) + * REMOVE - u8(0x01) u64(opaque) u64(seq_num) + * CULL - u8(0x02) u64(opaque) + * LOOKUP - u8(0x03) u128(token) u64(idx) + */ +enum { + CMD_ADD, + CMD_REMOVE, + CMD_CULL, + CMD_LOOKUP +}; + +int FuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + int rc = 0; + QUIC_SRTM *srtm = NULL; + PACKET pkt; + unsigned int cmd; + uint64_t arg_opaque, arg_seq_num, arg_idx; + QUIC_STATELESS_RESET_TOKEN arg_token; + + if ((srtm = ossl_quic_srtm_new(NULL, NULL)) == NULL) { + rc = -1; + goto err; + } + + if (!PACKET_buf_init(&pkt, buf, len)) + goto err; + + while (PACKET_remaining(&pkt) > 0) { + if (!PACKET_get_1(&pkt, &cmd)) + goto err; + + switch (cmd) { + case CMD_ADD: + if (!PACKET_get_net_8(&pkt, &arg_opaque) + || !PACKET_get_net_8(&pkt, &arg_seq_num) + || !PACKET_copy_bytes(&pkt, arg_token.token, + sizeof(arg_token.token))) + continue; /* just stop */ + + ossl_quic_srtm_add(srtm, (void *)(uintptr_t)arg_opaque, + arg_seq_num, &arg_token); + ossl_quic_srtm_check(srtm); + break; + + case CMD_REMOVE: + if (!PACKET_get_net_8(&pkt, &arg_opaque) + || !PACKET_get_net_8(&pkt, &arg_seq_num)) + continue; /* just stop */ + + ossl_quic_srtm_remove(srtm, (void *)(uintptr_t)arg_opaque, + arg_seq_num); + ossl_quic_srtm_check(srtm); + break; + + case CMD_CULL: + if (!PACKET_get_net_8(&pkt, &arg_opaque)) + continue; /* just stop */ + + ossl_quic_srtm_cull(srtm, (void *)(uintptr_t)arg_opaque); + ossl_quic_srtm_check(srtm); + break; + + case CMD_LOOKUP: + if (!PACKET_copy_bytes(&pkt, arg_token.token, + sizeof(arg_token.token)) + || !PACKET_get_net_8(&pkt, &arg_idx)) + continue; /* just stop */ + + ossl_quic_srtm_lookup(srtm, &arg_token, (size_t)arg_idx, + NULL, NULL); + ossl_quic_srtm_check(srtm); + break; + + default: + /* Other bytes are treated as no-ops */ + continue; + } + } + +err: + ossl_quic_srtm_free(srtm); + return rc; +} + +void FuzzerCleanup(void) +{ + FuzzerClearRand(); +} diff --git a/include/internal/quic_srtm.h b/include/internal/quic_srtm.h new file mode 100644 index 0000000000000000000000000000000000000000..9a2c18fdf33a02afbace48b411bcd466ba536751 --- /dev/null +++ b/include/internal/quic_srtm.h @@ -0,0 +1,109 @@ +/* +* Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +* +* Licensed under the Apache License 2.0 (the "License"). You may not use +* this file except in compliance with the License. You can obtain a copy +* in the file LICENSE in the source distribution or at +* https://www.openssl.org/source/license.html +*/ + +#ifndef OSSL_INTERNAL_QUIC_SRTM_H +# define OSSL_INTERNAL_QUIC_SRTM_H +# pragma once + +# include "internal/e_os.h" +# include "internal/time.h" +# include "internal/quic_types.h" +# include "internal/quic_wire.h" + +# ifndef OPENSSL_NO_QUIC + +/* + * QUIC Stateless Reset Token Manager + * ================================== + * + * The stateless reset token manager is responsible for mapping stateless reset + * tokens to connections. It is used to identify stateless reset tokens in + * incoming packets. In this regard it can be considered an alternate "routing" + * mechanism for incoming packets, and is somewhat analagous with the LCIDM, + * except that it uses SRTs to route rather than DCIDs. + * + * The SRTM specifically stores a bidirectional mapping of the form + * + * (opaque pointer, sequence number) [1] <-> [0..n] SRT + * + * The (opaque pointer, sequence number) tuple is used to refer to an entry (for + * example for the purposes of removing it later when it is no longer needed). + * Likewise, an entry can be looked up using SRT to get the opaque pointer and + * sequence number. + * + * It is important to note that the same SRT may exist multiple times and map to + * multiple (opaque pointer, sequence number) tuples, for example, if we + * initiate multiple connections to the same peer using the same local QUIC_PORT + * and the peer decides to behave bizarrely and issue the same SRT for both + * connections. It should not do this, but we have to be resilient against + * byzantine peer behaviour. Thus we are capable of storing multiple identical + * SRTs for different (opaque pointer, sequence number) keys. + * + * The SRTM supports arbitrary insertion, arbitrary deletion of specific keys + * identified by a (opaque pointer, sequence number) key, and mass deletion of + * all entries under a specific opaque pointer. It supports lookup by SRT to + * identify zero or more corresponding (opaque pointer, sequence number) tuples. + * + * The opaque pointer may be used for any purpose but is intended to represent a + * connection identity and must therefore be consistent (usefully comparable). + */ +typedef struct quic_srtm_st QUIC_SRTM; + +/* Creates a new empty SRTM instance. */ +QUIC_SRTM *ossl_quic_srtm_new(OSSL_LIB_CTX *libctx, const char *propq); + +/* Frees a SRTM instance. No-op if srtm is NULL. */ +void ossl_quic_srtm_free(QUIC_SRTM *srtm); + +/* + * Add a (opaque, seq_num) -> SRT entry to the SRTM. This operation fails if a + * SRT entry already exists with the same (opaque, seq_num) tuple. The token is + * copied. Returns 1 on success or 0 on failure. + */ +int ossl_quic_srtm_add(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num, + const QUIC_STATELESS_RESET_TOKEN *token); + +/* + * Removes an entry by identifying it via its (opaque, seq_num) tuple. + * Returns 1 if the entry was found and removed, and 0 if it was not found. + */ +int ossl_quic_srtm_remove(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num); + +/* + * Removes all entries (opaque, *) with the given opaque pointer. + * + * Returns 1 on success and 0 on failure. If no entries with the given opaque + * pointer were found, this is considered a success condition. + */ +int ossl_quic_srtm_cull(QUIC_SRTM *strm, void *opaque); + +/* + * Looks up a SRT to find the corresponding opaque pointer and sequence number. + * An output field pointer can be set to NULL if it is not required. + * + * This function is designed to avoid exposing timing channels on token values + * or the contents of the SRT mapping. + * + * If there are several identical SRTs, idx can be used to get the nth entry. + * Call this function with idx set to 0 first, and keep calling it after + * incrementing idx until it returns 0. + * + * Returns 1 if an entry was found and 0 otherwise. + */ +int ossl_quic_srtm_lookup(QUIC_SRTM *srtm, + const QUIC_STATELESS_RESET_TOKEN *token, + size_t idx, + void **opaque, uint64_t *seq_num); + +/* Verify internal invariants and assert if they are not met. */ +void ossl_quic_srtm_check(const QUIC_SRTM *srtm); + +# endif + +#endif diff --git a/providers/implementations/signature/sm2_sig.c b/providers/implementations/signature/sm2_sig.c index a61fd0864f1416e4bcccfde63644a47d45f14234..479e4eebe8eff03893cf5161dab223302864fd9d 100644 --- a/providers/implementations/signature/sm2_sig.c +++ b/providers/implementations/signature/sm2_sig.c @@ -329,6 +329,7 @@ static void sm2sig_freectx(void *vpsm2ctx) free_md(ctx); EC_KEY_free(ctx->ec); + OPENSSL_free(ctx->propq); OPENSSL_free(ctx->id); OPENSSL_free(ctx); } @@ -344,13 +345,21 @@ static void *sm2sig_dupctx(void *vpsm2ctx) *dstctx = *srcctx; dstctx->ec = NULL; + dstctx->propq = NULL; dstctx->md = NULL; dstctx->mdctx = NULL; + dstctx->id = NULL; if (srcctx->ec != NULL && !EC_KEY_up_ref(srcctx->ec)) goto err; dstctx->ec = srcctx->ec; + if (srcctx->propq != NULL) { + dstctx->propq = OPENSSL_strdup(srcctx->propq); + if (dstctx->propq == NULL) + goto err; + } + if (srcctx->md != NULL && !EVP_MD_up_ref(srcctx->md)) goto err; dstctx->md = srcctx->md; diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index be4ff02a897cd02e8c5e109a40e0488738a6410b..1ac0975d0a8faf6e4c47b8ae2015900734a39373 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -130,6 +130,17 @@ void dtls1_clear_sent_buffer(SSL_CONNECTION *s) while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) { frag = (hm_fragment *)item->data; + + if (frag->msg_header.is_ccs + && frag->msg_header.saved_retransmit_state.wrlmethod != NULL + && s->rlayer.wrl != frag->msg_header.saved_retransmit_state.wrl) { + /* + * If we're freeing the CCS then we're done with the old wrl and it + * can bee freed + */ + frag->msg_header.saved_retransmit_state.wrlmethod->free(frag->msg_header.saved_retransmit_state.wrl); + } + dtls1_hm_fragment_free(frag); pitem_free(item); } @@ -143,16 +154,16 @@ void dtls1_free(SSL *ssl) if (s == NULL) return; - DTLS_RECORD_LAYER_free(&s->rlayer); - - ssl3_free(ssl); - if (s->d1 != NULL) { dtls1_clear_queues(s); pqueue_free(s->d1->buffered_messages); pqueue_free(s->d1->sent_messages); } + DTLS_RECORD_LAYER_free(&s->rlayer); + + ssl3_free(ssl); + OPENSSL_free(s->d1); s->d1 = NULL; } diff --git a/ssl/quic/build.info b/ssl/quic/build.info index 3a9e2d55afdd38e39a04051eccf4140adc8d6905..866f581fa9113d2c81cf77d825fb17cdcb760634 100644 --- a/ssl/quic/build.info +++ b/ssl/quic/build.info @@ -14,3 +14,4 @@ SOURCE[$LIBSSL]=quic_tserver.c SOURCE[$LIBSSL]=quic_tls.c SOURCE[$LIBSSL]=quic_thread_assist.c SOURCE[$LIBSSL]=quic_trace.c +SOURCE[$LIBSSL]=quic_srtm.c diff --git a/ssl/quic/quic_srtm.c b/ssl/quic/quic_srtm.c new file mode 100644 index 0000000000000000000000000000000000000000..faa667253e6f4718a116f19b475fcbb4b6908d3a --- /dev/null +++ b/ssl/quic/quic_srtm.c @@ -0,0 +1,565 @@ +/* + * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/quic_srtm.h" +#include "internal/common.h" +#include +#include +#include + +/* + * QUIC Stateless Reset Token Manager + * ================================== + */ +typedef struct srtm_item_st SRTM_ITEM; + +#define BLINDED_SRT_LEN 16 + +DEFINE_LHASH_OF_EX(SRTM_ITEM); + +/* + * The SRTM is implemented using two LHASH instances, one matching opaque pointers to + * an item structure, and another matching a SRT-derived value to an item + * structure. Multiple items with different seq_num values under a given opaque, + * and duplicate SRTs, are handled using sorted singly-linked lists. + * + * The O(n) insert and lookup performance is tolerated on the basis that the + * total number of entries for a given opaque (total number of extant CIDs for a + * connection) should be quite small, and the QUIC protocol allows us to place a + * hard limit on this via the active_connection_id_limit TPARAM. Thus there is + * no risk of a large number of SRTs needing to be registered under a given + * opaque. + * + * It is expected one SRTM will exist per QUIC_PORT and track all SRTs across + * all connections for that QUIC_PORT. + */ +struct srtm_item_st { + SRTM_ITEM *next_by_srt_blinded; /* SORT BY opaque DESC */ + SRTM_ITEM *next_by_seq_num; /* SORT BY seq_num DESC */ + void *opaque; /* \__ unique identity for item */ + uint64_t seq_num; /* / */ + QUIC_STATELESS_RESET_TOKEN srt; + unsigned char srt_blinded[BLINDED_SRT_LEN]; /* H(srt) */ + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + uint32_t debug_token; +#endif +}; + +struct quic_srtm_st { + /* Crypto context used to calculate blinded SRTs H(srt). */ + EVP_CIPHER_CTX *blind_ctx; /* kept with key */ + + LHASH_OF(SRTM_ITEM) *items_fwd; /* (opaque) -> SRTM_ITEM */ + LHASH_OF(SRTM_ITEM) *items_rev; /* (H(srt)) -> SRTM_ITEM */ + + /* + * Monotonically transitions to 1 in event of allocation failure. The only + * valid operation on such an object is to free it. + */ + unsigned int alloc_failed : 1; +}; + +static unsigned long items_fwd_hash(const SRTM_ITEM *item) +{ + return (unsigned long)(uintptr_t)item->opaque; +} + +static int items_fwd_cmp(const SRTM_ITEM *a, const SRTM_ITEM *b) +{ + return a->opaque != b->opaque; +} + +static unsigned long items_rev_hash(const SRTM_ITEM *item) +{ + /* + * srt_blinded has already been through a crypto-grade hash function, so we + * can just use bits from that. + */ + unsigned long l; + + memcpy(&l, item->srt_blinded, sizeof(l)); + return l; +} + +static int items_rev_cmp(const SRTM_ITEM *a, const SRTM_ITEM *b) +{ + /* + * We don't need to use CRYPTO_memcmp here as the relationship of + * srt_blinded to srt is already cryptographically obfuscated. + */ + return memcmp(a->srt_blinded, b->srt_blinded, sizeof(a->srt_blinded)); +} + +static int srtm_check_lh(QUIC_SRTM *srtm, LHASH_OF(SRTM_ITEM) *lh) +{ + if (lh_SRTM_ITEM_error(lh)) { + srtm->alloc_failed = 1; + return 0; + } + + return 1; +} + +QUIC_SRTM *ossl_quic_srtm_new(OSSL_LIB_CTX *libctx, const char *propq) +{ + QUIC_SRTM *srtm = NULL; + unsigned char key[16]; + EVP_CIPHER *ecb = NULL; + + if (RAND_priv_bytes_ex(libctx, key, sizeof(key), sizeof(key) * 8) != 1) + goto err; + + if ((srtm = OPENSSL_zalloc(sizeof(*srtm))) == NULL) + return NULL; + + /* Use AES-128-ECB as a permutation over 128-bit SRTs. */ + if ((ecb = EVP_CIPHER_fetch(libctx, "AES-128-ECB", propq)) == NULL) + goto err; + + if ((srtm->blind_ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + + if (!EVP_EncryptInit_ex2(srtm->blind_ctx, ecb, key, NULL, NULL)) + goto err; + + EVP_CIPHER_free(ecb); + ecb = NULL; + + /* Create mappings. */ + if ((srtm->items_fwd = lh_SRTM_ITEM_new(items_fwd_hash, items_fwd_cmp)) == NULL + || (srtm->items_rev = lh_SRTM_ITEM_new(items_rev_hash, items_rev_cmp)) == NULL) + goto err; + + return srtm; + +err: + /* + * No cleansing of key needed as blinding exists only for side channel + * mitigation. + */ + ossl_quic_srtm_free(srtm); + EVP_CIPHER_free(ecb); + return NULL; +} + +static void srtm_free_each(SRTM_ITEM *ihead) +{ + SRTM_ITEM *inext, *item = ihead; + + for (item = item->next_by_seq_num; item != NULL; item = inext) { + inext = item->next_by_seq_num; + OPENSSL_free(item); + } + + OPENSSL_free(ihead); +} + +void ossl_quic_srtm_free(QUIC_SRTM *srtm) +{ + if (srtm == NULL) + return; + + lh_SRTM_ITEM_free(srtm->items_rev); + if (srtm->items_fwd != NULL) { + lh_SRTM_ITEM_doall(srtm->items_fwd, srtm_free_each); + lh_SRTM_ITEM_free(srtm->items_fwd); + } + + EVP_CIPHER_CTX_free(srtm->blind_ctx); + OPENSSL_free(srtm); +} + +/* + * Find a SRTM_ITEM by (opaque, seq_num). Returns NULL if no match. + * If head is non-NULL, writes the head of the relevant opaque list to *head if + * there is one. + * If prev is non-NULL, writes the previous node to *prev or NULL if it is + * the first item. + */ +static SRTM_ITEM *srtm_find(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num, + SRTM_ITEM **head_p, SRTM_ITEM **prev_p) +{ + SRTM_ITEM key, *item = NULL, *prev = NULL; + + key.opaque = opaque; + + item = lh_SRTM_ITEM_retrieve(srtm->items_fwd, &key); + if (head_p != NULL) + *head_p = item; + + for (; item != NULL; prev = item, item = item->next_by_seq_num) + if (item->seq_num == seq_num) { + break; + } else if (item->seq_num < seq_num) { + /* + * List is sorted in descending order so there can't be any match + * after this. + */ + item = NULL; + break; + } + + if (prev_p != NULL) + *prev_p = prev; + + return item; +} + +/* + * Inserts a SRTM_ITEM into the singly-linked by-sequence-number linked list. + * The new head pointer is written to *new_head (which may or may not be + * unchanged). + */ +static void sorted_insert_seq_num(SRTM_ITEM *head, SRTM_ITEM *item, SRTM_ITEM **new_head) +{ + uint64_t seq_num = item->seq_num; + SRTM_ITEM *cur = head, **fixup = new_head; + + *new_head = head; + + while (cur != NULL && cur->seq_num > seq_num) { + fixup = &cur->next_by_seq_num; + cur = cur->next_by_seq_num; + } + + item->next_by_seq_num = *fixup; + *fixup = item; +} + +/* + * Inserts a SRTM_ITEM into the singly-linked by-SRT list. + * The new head pointer is written to *new_head (which may or may not be + * unchanged). + */ +static void sorted_insert_srt(SRTM_ITEM *head, SRTM_ITEM *item, SRTM_ITEM **new_head) +{ + uintptr_t opaque = (uintptr_t)item->opaque; + SRTM_ITEM *cur = head, **fixup = new_head; + + *new_head = head; + + while (cur != NULL && (uintptr_t)cur->opaque > opaque) { + fixup = &cur->next_by_srt_blinded; + cur = cur->next_by_srt_blinded; + } + + item->next_by_srt_blinded = *fixup; + *fixup = item; +} + +/* + * Computes the blinded SRT value used for internal lookup for side channel + * mitigation purposes. We compute this once as a cached value when an SRTM_ITEM + * is formed. + */ +static int srtm_compute_blinded(QUIC_SRTM *srtm, SRTM_ITEM *item, + const QUIC_STATELESS_RESET_TOKEN *token) +{ + int outl = 0; + + /* + * We use AES-128-ECB as a permutation using a random key to facilitate + * blinding for side-channel purposes. Encrypt the token as a single AES + * block. + */ + if (!EVP_EncryptUpdate(srtm->blind_ctx, item->srt_blinded, &outl, + (const unsigned char *)token, sizeof(*token))) + return 0; + + if (!ossl_assert(outl == sizeof(*token))) + return 0; + + return 1; +} + +int ossl_quic_srtm_add(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num, + const QUIC_STATELESS_RESET_TOKEN *token) +{ + SRTM_ITEM *item = NULL, *head = NULL, *new_head, *r_item; + + if (srtm->alloc_failed) + return 0; + + /* (opaque, seq_num) duplicates not allowed */ + if ((item = srtm_find(srtm, opaque, seq_num, &head, NULL)) != NULL) + return 0; + + if ((item = OPENSSL_zalloc(sizeof(*item))) == NULL) + return 0; + + item->opaque = opaque; + item->seq_num = seq_num; + item->srt = *token; + if (!srtm_compute_blinded(srtm, item, &item->srt)) { + OPENSSL_free(item); + return 0; + } + + /* Add to forward mapping. */ + if (head == NULL) { + /* First item under this opaque */ + lh_SRTM_ITEM_insert(srtm->items_fwd, item); + if (!srtm_check_lh(srtm, srtm->items_fwd)) { + OPENSSL_free(item); + return 0; + } + } else { + sorted_insert_seq_num(head, item, &new_head); + if (new_head != head) { /* head changed, update in lhash */ + lh_SRTM_ITEM_insert(srtm->items_fwd, new_head); + if (!srtm_check_lh(srtm, srtm->items_fwd)) { + OPENSSL_free(item); + return 0; + } + } + } + + /* Add to reverse mapping. */ + r_item = lh_SRTM_ITEM_retrieve(srtm->items_rev, item); + if (r_item == NULL) { + /* First item under this blinded SRT */ + lh_SRTM_ITEM_insert(srtm->items_rev, item); + if (!srtm_check_lh(srtm, srtm->items_rev)) + /* + * Can't free the item now as we would have to undo the insertion + * into the forward mapping which would require an insert operation + * to restore the previous value. which might also fail. However, + * the item will be freed OK when we free the entire SRTM. + */ + return 0; + } else { + sorted_insert_srt(r_item, item, &new_head); + if (new_head != r_item) { /* head changed, update in lhash */ + lh_SRTM_ITEM_insert(srtm->items_rev, new_head); + if (!srtm_check_lh(srtm, srtm->items_rev)) + /* As above. */ + return 0; + } + } + + return 1; +} + +/* Remove item from reverse mapping. */ +static int srtm_remove_from_rev(QUIC_SRTM *srtm, SRTM_ITEM *item) +{ + SRTM_ITEM *rh_item; + + rh_item = lh_SRTM_ITEM_retrieve(srtm->items_rev, item); + assert(rh_item != NULL); + if (rh_item == item) { + /* + * Change lhash to point to item after this one, or remove the entry if + * this is the last one. + */ + if (item->next_by_srt_blinded != NULL) { + lh_SRTM_ITEM_insert(srtm->items_rev, item->next_by_srt_blinded); + if (!srtm_check_lh(srtm, srtm->items_rev)) + return 0; + } else { + lh_SRTM_ITEM_delete(srtm->items_rev, item); + } + } else { + /* Find our entry in the SRT list */ + for (; rh_item->next_by_srt_blinded != item; + rh_item = rh_item->next_by_srt_blinded); + rh_item->next_by_srt_blinded = item->next_by_srt_blinded; + } + + return 1; +} + +int ossl_quic_srtm_remove(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num) +{ + SRTM_ITEM *item, *prev = NULL; + + if (srtm->alloc_failed) + return 0; + + if ((item = srtm_find(srtm, opaque, seq_num, NULL, &prev)) == NULL) + /* No match */ + return 0; + + /* Remove from forward mapping. */ + if (prev == NULL) { + /* + * Change lhash to point to item after this one, or remove the entry if + * this is the last one. + */ + if (item->next_by_seq_num != NULL) { + lh_SRTM_ITEM_insert(srtm->items_fwd, item->next_by_seq_num); + if (!srtm_check_lh(srtm, srtm->items_fwd)) + return 0; + } else { + lh_SRTM_ITEM_delete(srtm->items_fwd, item); + } + } else { + prev->next_by_seq_num = item->next_by_seq_num; + } + + /* Remove from reverse mapping. */ + if (!srtm_remove_from_rev(srtm, item)) + return 0; + + OPENSSL_free(item); + return 1; +} + +int ossl_quic_srtm_cull(QUIC_SRTM *srtm, void *opaque) +{ + SRTM_ITEM key, *item = NULL, *inext, *ihead; + + key.opaque = opaque; + + if (srtm->alloc_failed) + return 0; + + if ((ihead = lh_SRTM_ITEM_retrieve(srtm->items_fwd, &key)) == NULL) + return 1; /* nothing removed is a success condition */ + + for (item = ihead; item != NULL; item = inext) { + inext = item->next_by_seq_num; + if (item != ihead) { + srtm_remove_from_rev(srtm, item); + OPENSSL_free(item); + } + } + + lh_SRTM_ITEM_delete(srtm->items_fwd, ihead); + srtm_remove_from_rev(srtm, ihead); + OPENSSL_free(ihead); + return 1; +} + +int ossl_quic_srtm_lookup(QUIC_SRTM *srtm, + const QUIC_STATELESS_RESET_TOKEN *token, + size_t idx, + void **opaque, uint64_t *seq_num) +{ + SRTM_ITEM key, *item; + + if (srtm->alloc_failed) + return 0; + + if (!srtm_compute_blinded(srtm, &key, token)) + return 0; + + item = lh_SRTM_ITEM_retrieve(srtm->items_rev, &key); + for (; idx > 0 && item != NULL; --idx, item = item->next_by_srt_blinded); + if (item == NULL) + return 0; + + if (opaque != NULL) + *opaque = item->opaque; + if (seq_num != NULL) + *seq_num = item->seq_num; + + return 1; +} + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + +static uint32_t token_next = 0x5eadbeef; +static size_t tokens_seen; + +struct check_args { + uint32_t token; + int mode; +}; + +static void check_mark(SRTM_ITEM *item, void *arg) +{ + struct check_args *arg_ = arg; + uint32_t token = arg_->token; + uint64_t prev_seq_num; + void *prev_opaque; + int have_prev = 0; + + assert(item != NULL); + + while (item != NULL) { + if (have_prev) { + assert(!(item->opaque == prev_opaque && item->seq_num == prev_seq_num)); + if (!arg_->mode) + assert(item->opaque != prev_opaque || item->seq_num < prev_seq_num); + } + + ++tokens_seen; + item->debug_token = token; + prev_opaque = item->opaque; + prev_seq_num = item->seq_num; + have_prev = 1; + + if (arg_->mode) + item = item->next_by_srt_blinded; + else + item = item->next_by_seq_num; + } +} + +static void check_count(SRTM_ITEM *item, void *arg) +{ + struct check_args *arg_ = arg; + uint32_t token = arg_->token; + + assert(item != NULL); + + while (item != NULL) { + ++tokens_seen; + assert(item->debug_token == token); + + if (arg_->mode) + item = item->next_by_seq_num; + else + item = item->next_by_srt_blinded; + } +} + +#endif + +void ossl_quic_srtm_check(const QUIC_SRTM *srtm) +{ +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + struct check_args args = {0}; + size_t tokens_expected, tokens_expected_old; + + args.token = token_next; + ++token_next; + + assert(srtm != NULL); + assert(srtm->blind_ctx != NULL); + assert(srtm->items_fwd != NULL); + assert(srtm->items_rev != NULL); + + tokens_seen = 0; + lh_SRTM_ITEM_doall_arg(srtm->items_fwd, check_mark, &args); + + tokens_expected = tokens_seen; + tokens_seen = 0; + lh_SRTM_ITEM_doall_arg(srtm->items_rev, check_count, &args); + + assert(tokens_seen == tokens_expected); + tokens_expected_old = tokens_expected; + + args.token = token_next; + ++token_next; + + args.mode = 1; + tokens_seen = 0; + lh_SRTM_ITEM_doall_arg(srtm->items_rev, check_mark, &args); + + tokens_expected = tokens_seen; + tokens_seen = 0; + lh_SRTM_ITEM_doall_arg(srtm->items_fwd, check_count, &args); + + assert(tokens_seen == tokens_expected); + assert(tokens_seen == tokens_expected_old); +#endif +} diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 5314e1ec0dc7a5d29f3ed19364e647f9132bcbcd..70d3b17c19e0bf28552b8e0640d1e05cdeff09af 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -327,11 +327,13 @@ static int dane_tlsa_add(SSL_DANE *dane, case DANETLS_SELECTOR_CERT: if (!d2i_X509(&cert, &p, ilen) || p < data || dlen != (size_t)(p - data)) { + X509_free(cert); tlsa_free(t); ERR_raise(ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE); return 0; } if (X509_get0_pubkey(cert) == NULL) { + X509_free(cert); tlsa_free(t); ERR_raise(ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_CERTIFICATE); return 0; @@ -339,6 +341,7 @@ static int dane_tlsa_add(SSL_DANE *dane, if ((DANETLS_USAGE_BIT(usage) & DANETLS_TA_MASK) == 0) { X509_free(cert); + tlsa_free(t); break; } @@ -362,6 +365,7 @@ static int dane_tlsa_add(SSL_DANE *dane, case DANETLS_SELECTOR_SPKI: if (!d2i_PUBKEY(&pkey, &p, ilen) || p < data || dlen != (size_t)(p - data)) { + EVP_PKEY_free(pkey); tlsa_free(t); ERR_raise(ERR_LIB_SSL, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY); return 0; diff --git a/ssl/statem/extensions_cust.c b/ssl/statem/extensions_cust.c index 7c049d29707257550a51de9c2ef531735bd8a26a..fd840e8918e833ff5fe9cda417869e299a07f070 100644 --- a/ssl/statem/extensions_cust.c +++ b/ssl/statem/extensions_cust.c @@ -342,6 +342,8 @@ void custom_exts_free(custom_ext_methods *exts) OPENSSL_free(meth->parse_arg); } OPENSSL_free(exts->meths); + exts->meths = NULL; + exts->meths_count = 0; } /* Return true if a client custom extension exists, false otherwise */ diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c index a88b0dfeac61af992b9c28e6289c2f1c4f45d937..c674ddfb54df534cd2e178e9fc175c646528a999 100644 --- a/ssl/statem/statem_dtls.c +++ b/ssl/statem/statem_dtls.c @@ -62,7 +62,7 @@ static hm_fragment *dtls1_hm_fragment_new(size_t frag_len, int reassembly) unsigned char *buf = NULL; unsigned char *bitmask = NULL; - if ((frag = OPENSSL_malloc(sizeof(*frag))) == NULL) + if ((frag = OPENSSL_zalloc(sizeof(*frag))) == NULL) return NULL; if (frag_len) { @@ -94,14 +94,7 @@ void dtls1_hm_fragment_free(hm_fragment *frag) { if (!frag) return; - if (frag->msg_header.is_ccs) { - /* - * If we're freeing the CCS then we're done with the old wrl and it - * can bee freed - */ - if (frag->msg_header.saved_retransmit_state.wrlmethod != NULL) - frag->msg_header.saved_retransmit_state.wrlmethod->free(frag->msg_header.saved_retransmit_state.wrl); - } + OPENSSL_free(frag->fragment); OPENSSL_free(frag->reassembly); OPENSSL_free(frag); diff --git a/test/build.info b/test/build.info index 10f29b19cfb2981e5c01b928636bcc07a74a1610..cba48e6db00de2571e9a114cad7867b29b83c167 100644 --- a/test/build.info +++ b/test/build.info @@ -328,6 +328,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[quic_txpim_test]=../include ../apps/include DEPEND[quic_txpim_test]=../libcrypto.a ../libssl.a libtestutil.a + SOURCE[quic_srtm_test]=quic_srtm_test.c + INCLUDE[quic_srtm_test]=../include ../apps/include + DEPEND[quic_srtm_test]=../libcrypto.a ../libssl.a libtestutil.a + SOURCE[quic_fifd_test]=quic_fifd_test.c cc_dummy.c INCLUDE[quic_fifd_test]=../include ../apps/include DEPEND[quic_fifd_test]=../libcrypto.a ../libssl.a libtestutil.a @@ -1129,6 +1133,7 @@ ENDIF IF[{- !$disabled{'quic'} -}] PROGRAMS{noinst}=quic_wire_test quic_ackm_test quic_record_test PROGRAMS{noinst}=quic_fc_test quic_stream_test quic_cfq_test quic_txpim_test + PROGRAMS{noinst}=quic_srtm_test PROGRAMS{noinst}=quic_fifd_test quic_txp_test quic_tserver_test PROGRAMS{noinst}=quic_client_test quic_cc_test quic_multistream_test ENDIF diff --git a/test/quic_srtm_test.c b/test/quic_srtm_test.c new file mode 100644 index 0000000000000000000000000000000000000000..558e323cd6ea25ad918bbe3ecdb50fe6c176513d --- /dev/null +++ b/test/quic_srtm_test.c @@ -0,0 +1,84 @@ +/* + * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/quic_srtm.h" +#include "testutil.h" + +static char ptrs[8]; + +static const QUIC_STATELESS_RESET_TOKEN token_1 = {{ + 0x01, 0x02, 0x03, 0x04 +}}; + +static const QUIC_STATELESS_RESET_TOKEN token_2 = {{ + 0x01, 0x02, 0x03, 0x05 +}}; + +static int test_srtm(void) +{ + int testresult = 0; + QUIC_SRTM *srtm; + void *opaque = NULL; + uint64_t seq_num = 0; + + if (!TEST_ptr(srtm = ossl_quic_srtm_new(NULL, NULL))) + goto err; + + if (!TEST_true(ossl_quic_srtm_add(srtm, ptrs + 0, 0, &token_1)) + || !TEST_false(ossl_quic_srtm_add(srtm, ptrs + 0, 0, &token_1)) + || !TEST_false(ossl_quic_srtm_remove(srtm, ptrs + 0, 1)) + || !TEST_false(ossl_quic_srtm_remove(srtm, ptrs + 3, 0)) + || !TEST_true(ossl_quic_srtm_cull(srtm, ptrs + 3)) + || !TEST_true(ossl_quic_srtm_cull(srtm, ptrs + 3)) + || !TEST_true(ossl_quic_srtm_add(srtm, ptrs + 0, 1, &token_1)) + || !TEST_true(ossl_quic_srtm_add(srtm, ptrs + 0, 2, &token_1)) + || !TEST_true(ossl_quic_srtm_add(srtm, ptrs + 0, 3, &token_1)) + || !TEST_true(ossl_quic_srtm_add(srtm, ptrs + 1, 0, &token_1)) + || !TEST_true(ossl_quic_srtm_add(srtm, ptrs + 2, 0, &token_2)) + || !TEST_true(ossl_quic_srtm_add(srtm, ptrs + 3, 3, &token_2)) + || !TEST_true(ossl_quic_srtm_remove(srtm, ptrs + 3, 3)) + || !TEST_true(ossl_quic_srtm_lookup(srtm, &token_1, 0, &opaque, &seq_num)) + || !TEST_ptr_eq(opaque, ptrs + 1) + || !TEST_uint64_t_eq(seq_num, 0) + || !TEST_true(ossl_quic_srtm_lookup(srtm, &token_1, 1, &opaque, &seq_num)) + || !TEST_ptr_eq(opaque, ptrs + 0) + || !TEST_uint64_t_eq(seq_num, 3) + || !TEST_true(ossl_quic_srtm_lookup(srtm, &token_1, 2, &opaque, &seq_num)) + || !TEST_ptr_eq(opaque, ptrs + 0) + || !TEST_uint64_t_eq(seq_num, 2) + || !TEST_true(ossl_quic_srtm_lookup(srtm, &token_1, 3, &opaque, &seq_num)) + || !TEST_ptr_eq(opaque, ptrs + 0) + || !TEST_uint64_t_eq(seq_num, 1) + || !TEST_true(ossl_quic_srtm_lookup(srtm, &token_1, 4, &opaque, &seq_num)) + || !TEST_ptr_eq(opaque, ptrs + 0) + || !TEST_uint64_t_eq(seq_num, 0) + || !TEST_false(ossl_quic_srtm_lookup(srtm, &token_1, 5, &opaque, &seq_num)) + || !TEST_true(ossl_quic_srtm_cull(srtm, ptrs + 0)) + || !TEST_true(ossl_quic_srtm_lookup(srtm, &token_1, 0, &opaque, &seq_num)) + || !TEST_ptr_eq(opaque, ptrs + 1) + || !TEST_uint64_t_eq(seq_num, 0) + || !TEST_true(ossl_quic_srtm_lookup(srtm, &token_2, 0, &opaque, &seq_num)) + || !TEST_ptr_eq(opaque, ptrs + 2) + || !TEST_uint64_t_eq(seq_num, 0) + || !TEST_true(ossl_quic_srtm_remove(srtm, ptrs + 2, 0)) + || !TEST_false(ossl_quic_srtm_lookup(srtm, &token_2, 0, &opaque, &seq_num)) + ) + goto err; + + testresult = 1; +err: + ossl_quic_srtm_free(srtm); + return testresult; +} + +int setup_tests(void) +{ + ADD_TEST(test_srtm); + return 1; +} diff --git a/test/recipes/70-test_quic_srtm.t b/test/recipes/70-test_quic_srtm.t new file mode 100644 index 0000000000000000000000000000000000000000..4b6818ab92835970d5e49c46ef9634ff283a1154 --- /dev/null +++ b/test/recipes/70-test_quic_srtm.t @@ -0,0 +1,19 @@ +#! /usr/bin/env perl +# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use OpenSSL::Test; +use OpenSSL::Test::Utils; + +setup("test_quic_srtm"); + +plan skip_all => "QUIC protocol is not supported by this OpenSSL build" + if disabled('quic'); + +plan tests => 1; + +ok(run(test(["quic_srtm_test"]))); diff --git a/test/recipes/99-test_fuzz_quic_srtm.t b/test/recipes/99-test_fuzz_quic_srtm.t new file mode 100644 index 0000000000000000000000000000000000000000..de27a8764a1f56eabb3e6a68aa95125e87a78a93 --- /dev/null +++ b/test/recipes/99-test_fuzz_quic_srtm.t @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use warnings; + +use OpenSSL::Test qw/:DEFAULT srctop_file/; +use OpenSSL::Test::Utils; + +my $fuzzer = "quic-srtm"; +setup("test_fuzz_${fuzzer}"); + +plan skip_all => "This test requires quic support" + if disabled("quic"); + +plan tests => 2; # one more due to below require_ok(...) + +require_ok(srctop_file('test','recipes','fuzz.pl')); + +fuzz_ok($fuzzer); diff --git a/util/perl/OpenSSL/config.pm b/util/perl/OpenSSL/config.pm index 791b19847ad85d4733c6a10bd296077ca5bc2c5d..8125f48b1452ee7e19edfcad72467a8b70a14023 100755 --- a/util/perl/OpenSSL/config.pm +++ b/util/perl/OpenSSL/config.pm @@ -359,8 +359,15 @@ sub determine_compiler_settings { # However, other letters have been seen as well (for example X), # and it's documented that HP (now VSI) reserve the letter W, X, # Y and Z for their own uses. - my ($vendor, $version) = - ( $v =~ m/^([A-Z]+) C [VWXYZ]([0-9\.-]+)(:? +\(.*?\))? on / ); + my ($vendor, $arch, $version, $extra) = + ( $v =~ m/^ + ([A-Z]+) # Usually VSI + \s+ C + (?:\s+(.*?))? # Possible build arch + \s+ [VWXYZ]([0-9\.-]+) # Version + (?:\s+\((.*?)\))? # Possible extra data + \s+ on + /x ); my ($major, $minor, $patch) = ( $version =~ m/^([0-9]+)\.([0-9]+)-0*?(0|[1-9][0-9]*)$/ ); $CC = 'CC';