Conversation
5f54234 to
c37bd2f
Compare
|
Retest this please AgentOfflineException |
622feb1 to
1814bce
Compare
### `wolfssl/internal.h`
- **`InternalTicket` struct gains a flexible array member**: A new `peerCert[]` field (with a preceding `peerCertLen[2]`) is added to `InternalTicket`. This allows the peer's DER-encoded certificate to be stored directly inside the session ticket.
- **`ExternalTicket` struct becomes variable-length**: The `enc_ticket` field is changed from a fixed-size array to a flexible array member (`byte enc_ticket[]`). The `mac` field is removed from the struct — the MAC is now placed dynamically after the encrypted data in `enc_ticket`.
### `src/internal.c`
- The `GetRecordHeader` function now only adds `MAX_COMP_EXTRA` to the maximum allowed record size when `ssl->options.usingCompression` is true, tightening the length validation. The max fragment length extension check is now much stricter.
- **Peer certificate is serialized into the ticket**: During ticket creation, the code attempts to find the peer certificate from `ssl->peerCert` or from `ssl->session->chain` (fallback). If found and within `MAX_TICKET_PEER_CERT_SZ`, it's copied into `it->peerCert`. DTLS is explicitly excluded (peer cert length set to 0) to keep ticket size small for MTU constraints. If `HAVE_MAX_FRAGMENT` is defined and max fragment is not `MAX_RECORD_SIZE` for TLS 1.3, the cert is also skipped since `SendTls13NewSessionTicket` doesn't support fragmentation yet.
- **Peer certificate restoration from ticket**: On successful ticket decryption, if the ticket contains a peer certificate (`peerCertLen > 0`), it is decoded back into `ssl->peerCert` via `ParseCertRelative`/`CopyDecodedToX509`, and also added to `ssl->session->chain` via `AddSessionCertToChain`.
- The `CLEAR_ASN_NO_PEM_HEADER_ERROR` macro was rewritten to loop and remove all consecutive PEM no-start-line errors (not just the last one), wrapped in a `do { ... } while(0)` for safety.
- The `SendTicket` function is simplified to use `SendHandshakeMsg` to support fragmenting the larger ticket.
---
### `src/x509.c`
- `loadX509orX509REQFromPemBio` now accepts `TRUSTED_CERT_TYPE` in addition to `CERT_TYPE` and `CERTREQ_TYPE`.
- **Streaming BIO support**: When `wolfSSL_BIO_get_len()` returns ≤ 0 (e.g., pipes/FIFOs), the function no longer returns an error. Instead, it sets an initial buffer of `MAX_X509_SIZE` and dynamically grows (doubling) up to `MAX_BIO_READ_BUFFER` (`MAX_X509_SIZE * 16`) as data is read byte-by-byte.
- **Alternate footer detection**: For `TRUSTED_CERT_TYPE`, the PEM reader also checks for the regular `CERT_TYPE` footer (`-----END CERTIFICATE-----`) in addition to the trusted cert footer (`-----END TRUSTED CERTIFICATE-----`), so it can parse either format.
- Removed two lines that set `cert->srcIdx` to `SIGALGO_SEQ` offset. This makes `cert->srcIdx` reflect the end of parsed certificate data. This is used by `loadX509orX509REQFromBuffer` to detect where auxiliary trust data begins in trusted certificates.
---
### `src/ssl_sk.c`
- Added a `STACK_TYPE_X509_CRL` case to `wolfssl_sk_dup_data` that calls `wolfSSL_X509_CRL_dup` for deep-copying CRL stack elements. Previously, `STACK_TYPE_X509_CRL` fell through to the unsupported default case.
---
### `wolfssl/openssl/ssl.h`
- `sk_X509_dup` now maps to `wolfSSL_shallow_sk_dup` (was `wolfSSL_sk_dup`/deep copy). This matches OpenSSL's behavior where `sk_X509_dup` does a shallow copy.
- `sk_SSL_CIPHER_dup` similarly changed to `wolfSSL_shallow_sk_dup`.
---
### `src/ssl_api_cert.c`
- When `ssl->ourCert` is `NULL` and the SSL owns its cert, the function now checks if `ssl->ctx->ourCert` points to the same certificate (by comparing DER buffers). If so, it returns the ctx's `X509` pointer directly. This maintains pointer compatibility for applications (like nginx OCSP stapling) that use the `X509*` from `SSL_CTX_use_certificate` as a lookup key.
### `src/bio.c`
- When `wolfssl_file_len` returns `WOLFSSL_BAD_FILETYPE` (now returned for pipes/FIFOs), `wolfSSL_BIO_get_len` treats it as length 0 instead of propagating the error.
---
### `tests/test-maxfrag.conf` and `tests/test-maxfrag-dtls.conf`
- Removed `DHE-RSA-AES256-GCM-SHA384` test entries because the ClientKeyExchange doesn't fit in the selected max fragment length.
1814bce to
9192db1
Compare
| #endif | ||
|
|
||
| /* Calculate actual internal ticket size */ | ||
| #if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ |
There was a problem hiding this comment.
Just add after setting the common base.
internalTicketSz = WOLF...
#if defined...
internalTicketSz += peerCertSz;
#endif
|
|
||
| #if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ | ||
| !defined(NO_CERT_IN_TICKET) | ||
| /* Restore peer certificate from ticket to session chain and peerCert */ |
There was a problem hiding this comment.
Extract to new function.
| ssl->buffers.weOwnKey = 1; | ||
| } | ||
| else { | ||
| if (ssl->buffers.key != NULL && ssl->buffers.weOwnKey) |
There was a problem hiding this comment.
Should be able to move this out.
Both branches of if statement free it if not NULL and we own it.
| if (ssl->buffers.weOwnAltKey) { | ||
| WOLFSSL_MSG("Unloading alt key"); | ||
| ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); | ||
| if (ssl->buffers.altKey != NULL && ssl->buffers.altKey->buffer != NULL) |
There was a problem hiding this comment.
Pull request overview
This PR implements fixes for nginx 1.28.1 compatibility, primarily addressing session ticket handling and certificate management. The changes enable peer certificates to be stored in session tickets and add support for streaming BIO sources.
Changes:
- Modified session ticket structures to support variable-length peer certificates
- Enhanced PEM reading to handle streaming sources (pipes/FIFOs)
- Updated stack operations for proper shallow/deep copying semantics
- Fixed memory handling in certificate and key management
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| wolfssl/internal.h | Made session ticket structures variable-length to store peer certificates; moved MAX_PSK_ID_LEN definition |
| src/internal.c | Added peer certificate serialization/restoration in tickets; improved ticket encryption/decryption |
| src/x509.c | Added streaming BIO support; implemented TRUSTED_CERT_TYPE parsing; refactored AIA string handling |
| wolfssl/openssl/ssl.h | Changed sk_X509_dup and sk_SSL_CIPHER_dup to shallow copy semantics |
| src/ssl_sk.c | Implemented X509_CRL deep copy support in stack duplication |
| src/ssl_api_cert.c | Added certificate pointer compatibility check for nginx OCSP stapling |
| src/bio.c | Handled WOLFSSL_BAD_FILETYPE for pipe/FIFO sources |
| wolfssl/ssl.h | Added X509_CRL_new_null and X509_CRL_up_ref function declarations |
| src/crl.c | Implemented X509_CRL_up_ref for reference counting |
| tests/test-maxfrag*.conf | Removed DHE-RSA-AES256-GCM-SHA384 tests that don't fit in max fragment |
| .github/workflows/nginx.yml | Updated workflow for nginx 1.28.1 testing with sanitizers |
| configure.ac | Added nginx to OPENSSLALL enable condition |
Comments suppressed due to low confidence (1)
src/internal.c:1
- Consider extracting the compression extra calculation into a named constant or inline function for better readability and reusability, as this pattern appears twice in consecutive blocks.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ | ||
| !defined(NO_CERT_IN_TICKET) | ||
| byte peerCertLen[OPAQUE16_LEN]; /* peer cert length */ | ||
| byte peerCert[]; /* peer certificate DER - variable length */ |
There was a problem hiding this comment.
The comment should clarify that this flexible array member must be the last field in the struct, as required by C standards. Consider adding '(must be last field)' to the comment.
| byte peerCert[]; /* peer certificate DER - variable length */ | |
| byte peerCert[]; /* peer certificate DER - variable length | |
| * (must be last field) */ |
| byte enc_ticket[]; /* encrypted ticket - var length | ||
| * + total mac - 32 */ |
There was a problem hiding this comment.
The multi-line comment format is inconsistent with the rest of the codebase. The comment should clarify that the MAC follows the encrypted data within this array, not as a separate field.
| byte enc_ticket[]; /* encrypted ticket - var length | |
| * + total mac - 32 */ | |
| byte enc_ticket[]; /* encrypted ticket data (var len) | |
| * followed by MAC bytes */ |
| /* attempt to read newline following footer */ | ||
| i++; | ||
| if (pem[i-1] == '\r') { | ||
| if (i < pemSz && pem[i-1] == '\r') { |
There was a problem hiding this comment.
The bounds check 'i < pemSz' is repeated three times in close proximity. Consider consolidating this logic to reduce duplication and improve maintainability.
| @@ -35,6 +35,8 @@ | |||
| #include <wolfssl/openssl/x509v3.h> | |||
| #endif | |||
|
|
|||
There was a problem hiding this comment.
This magic number '16' should be documented. Add a comment explaining why the buffer limit is set to 16 times MAX_X509_SIZE.
| /* Use a generous upper bound: allow BIO reads up to 16 times MAX_X509_SIZE | |
| * to account for encoding overhead and multiple concatenated certificates. */ |
| if (ssl->buffers.key != NULL && ssl->buffers.key->buffer != NULL) | ||
| ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); |
There was a problem hiding this comment.
The null check for ssl->buffers.key->buffer is good, but consider also checking if length is greater than 0 before calling ForceZero to avoid unnecessary function calls.
| --with-cc-opt='-fsanitize=address -DNGX_DEBUG_PALLOC=1 -g3 \ | ||
| ${{ env.nginx_c_flags }}' \ |
There was a problem hiding this comment.
The line continuation backslash on line 249 is inside the configure arguments. Ensure the shell properly handles this continuation within the single-quoted string.
| --with-cc-opt='-fsanitize=address -DNGX_DEBUG_PALLOC=1 -g3 \ | |
| ${{ env.nginx_c_flags }}' \ | |
| --with-cc-opt="-fsanitize=address -DNGX_DEBUG_PALLOC=1 -g3 ${{ env.nginx_c_flags }}" \ |
Depends on wolfSSL/wolfssl-nginx#31
wolfssl/internal.hInternalTicketstruct gains a flexible array member: A newpeerCert[]field (with a precedingpeerCertLen[2]) is added toInternalTicket. This allows the peer's DER-encoded certificate to be stored directly inside the session ticket.ExternalTicketstruct becomes variable-length: Theenc_ticketfield is changed from a fixed-size array to a flexible array member (byte enc_ticket[]). Themacfield is removed from the struct — the MAC is now placed dynamically after the encrypted data inenc_ticket.src/internal.cGetRecordHeaderfunction now only addsMAX_COMP_EXTRAto the maximum allowed record size whenssl->options.usingCompressionis true, tightening the length validation. The max fragment length extension check is now much stricter.ssl->peerCertor fromssl->session->chain(fallback). If found and withinMAX_TICKET_PEER_CERT_SZ, it's copied intoit->peerCert. DTLS is explicitly excluded (peer cert length set to 0) to keep ticket size small for MTU constraints. IfHAVE_MAX_FRAGMENTis defined and max fragment is notMAX_RECORD_SIZEfor TLS 1.3, the cert is also skipped sinceSendTls13NewSessionTicketdoesn't support fragmentation yet.peerCertLen > 0), it is decoded back intossl->peerCertviaParseCertRelative/CopyDecodedToX509, and also added tossl->session->chainviaAddSessionCertToChain.CLEAR_ASN_NO_PEM_HEADER_ERRORmacro was rewritten to loop and remove all consecutive PEM no-start-line errors (not just the last one), wrapped in ado { ... } while(0)for safety.SendTicketfunction is simplified to useSendHandshakeMsgto support fragmenting the larger ticket.src/x509.cloadX509orX509REQFromPemBionow acceptsTRUSTED_CERT_TYPEin addition toCERT_TYPEandCERTREQ_TYPE.wolfSSL_BIO_get_len()returns ≤ 0 (e.g., pipes/FIFOs), the function no longer returns an error. Instead, it sets an initial buffer ofMAX_X509_SIZEand dynamically grows (doubling) up toMAX_BIO_READ_BUFFER(MAX_X509_SIZE * 16) as data is read byte-by-byte.TRUSTED_CERT_TYPE, the PEM reader also checks for the regularCERT_TYPEfooter (-----END CERTIFICATE-----) in addition to the trusted cert footer (-----END TRUSTED CERTIFICATE-----), so it can parse either format.cert->srcIdxtoSIGALGO_SEQoffset. This makescert->srcIdxreflect the end of parsed certificate data. This is used byloadX509orX509REQFromBufferto detect where auxiliary trust data begins in trusted certificates.src/ssl_sk.cSTACK_TYPE_X509_CRLcase towolfssl_sk_dup_datathat callswolfSSL_X509_CRL_dupfor deep-copying CRL stack elements. Previously,STACK_TYPE_X509_CRLfell through to the unsupported default case.wolfssl/openssl/ssl.hsk_X509_dupnow maps towolfSSL_shallow_sk_dup(waswolfSSL_sk_dup/deep copy). This matches OpenSSL's behavior wheresk_X509_dupdoes a shallow copy.sk_SSL_CIPHER_dupsimilarly changed towolfSSL_shallow_sk_dup.src/ssl_api_cert.cssl->ourCertisNULLand the SSL owns its cert, the function now checks ifssl->ctx->ourCertpoints to the same certificate (by comparing DER buffers). If so, it returns the ctx'sX509pointer directly. This maintains pointer compatibility for applications (like nginx OCSP stapling) that use theX509*fromSSL_CTX_use_certificateas a lookup key.src/bio.cwolfssl_file_lenreturnsWOLFSSL_BAD_FILETYPE(now returned for pipes/FIFOs),wolfSSL_BIO_get_lentreats it as length 0 instead of propagating the error.tests/test-maxfrag.confandtests/test-maxfrag-dtls.confDHE-RSA-AES256-GCM-SHA384test entries because the ClientKeyExchange doesn't fit in the selected max fragment length.