From 97616f7601e6b5a021102fff09c2088cd85f9b6f Mon Sep 17 00:00:00 2001 From: Daiki AMINAKA <1991.daiki@gmail.com> Date: Sat, 31 Dec 2022 19:09:43 -0800 Subject: [PATCH] new API for async certificate validation (#3318) * new API for async certificate validation * Fix func pointer assignment * generate dotnet --- ...ConnectionCertificateValidationComplete.md | 40 ++++++++++ src/core/api.c | 74 +++++++++++++++++++ src/core/api.h | 8 ++ src/core/connection.c | 7 ++ src/core/library.c | 1 + src/core/operation.h | 5 ++ src/cs/lib/msquic_generated.cs | 3 + src/inc/msquic.h | 14 ++++ src/inc/quic_trace.h | 1 + src/lib.rs | 19 +++++ src/plugins/dbg/quictypes.h | 3 + src/test/lib/TestConnection.cpp | 6 +- src/tools/spin/spinquic.cpp | 7 ++ 13 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 docs/api/ConnectionCertificateValidationComplete.md diff --git a/docs/api/ConnectionCertificateValidationComplete.md b/docs/api/ConnectionCertificateValidationComplete.md new file mode 100644 index 000000000..5f2cf99b7 --- /dev/null +++ b/docs/api/ConnectionCertificateValidationComplete.md @@ -0,0 +1,40 @@ +ConnectionCertificateValidationComplete function +====== + +Uses the QUIC (client) handle to complete resumption ticket validation. This must be called after client app handles certificate validation and then return QUIC_STATUS_PENDING. + +# Syntax + +```C +typedef +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +(QUIC_API * QUIC_CONNECTION_COMP_CERT_FN)( + _In_ _Pre_defensive_ HQUIC Connection, + _In_ BOOLEAN Result + ); +``` + +# Parameters + +`Connection` + +The valid handle to an open connection object. + +`Result` + +Ticket validation result. + +# Return Value + +The function returns a [QUIC_STATUS](QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded. + +# Remarks + +- Available from v2.2 + +# See Also + +[ConnectionOpen](ConnectionStart.md)
+[ConnectionClose](ConnectionClose.md)
+[ConnectionShutdown](ConnectionShutdown.md)
diff --git a/src/core/api.c b/src/core/api.c index 4791845a1..478f14f60 100644 --- a/src/core/api.c +++ b/src/core/api.c @@ -1721,3 +1721,77 @@ Error: return Status; } + +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +QUIC_API +MsQuicConnectionCertificateValidationComplete( + _In_ _Pre_defensive_ HQUIC Handle, + _In_ BOOLEAN Result + ) +{ + QUIC_STATUS Status; + QUIC_CONNECTION* Connection; + QUIC_OPERATION* Oper; + + QuicTraceEvent( + ApiEnter, + "[ api] Enter %u (%p).", + QUIC_TRACE_API_CONNECTION_COMPLETE_CERTIFICATE_VALIDATION, + Handle); + + if (IS_CONN_HANDLE(Handle)) { +#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") + Connection = (QUIC_CONNECTION*)Handle; + } else if (IS_STREAM_HANDLE(Handle)) { +#pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") + QUIC_STREAM* Stream = (QUIC_STREAM*)Handle; + CXPLAT_TEL_ASSERT(!Stream->Flags.HandleClosed); + CXPLAT_TEL_ASSERT(!Stream->Flags.Freed); + Connection = Stream->Connection; + } else { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + + QUIC_CONN_VERIFY(Connection, !Connection->State.Freed); + + if (QuicConnIsServer(Connection)) { + Status = QUIC_STATUS_INVALID_PARAMETER; + goto Error; + } + + if (Connection->Crypto.TlsState.HandshakeComplete) { + Status = QUIC_STATUS_INVALID_STATE; + goto Error; + } + + Oper = QuicOperationAlloc(Connection->Worker, QUIC_OPER_TYPE_API_CALL); + if (Oper == NULL) { + Status = QUIC_STATUS_OUT_OF_MEMORY; + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "CONN_COMPLETE_CERTIFICATE_VALIDATION operation", + 0); + goto Error; + } + + Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_COMPLETE_CERTIFICATE_VALIDATION; + Oper->API_CALL.Context->CONN_COMPLETE_CERTIFICATE_VALIDATION.Result = Result; + + // + // Queue the operation but don't wait for the completion. + // + QuicConnQueueOper(Connection, Oper); + Status = QUIC_STATUS_PENDING; + +Error: + + QuicTraceEvent( + ApiExitStatus, + "[ api] Exit %u", + Status); + + return Status; +} diff --git a/src/core/api.h b/src/core/api.h index e1a15f60f..f8736b35d 100644 --- a/src/core/api.h +++ b/src/core/api.h @@ -269,3 +269,11 @@ MsQuicConnectionResumptionTicketValidationComplete( _In_ _Pre_defensive_ HQUIC Handle, _In_ BOOLEAN Result ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +QUIC_API +MsQuicConnectionCertificateValidationComplete( + _In_ _Pre_defensive_ HQUIC Handle, + _In_ BOOLEAN Result + ); diff --git a/src/core/connection.c b/src/core/connection.c index b01314fa2..c45c4a19c 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -7313,6 +7313,13 @@ QuicConnProcessApiOperation( ApiCtx->CONN_COMPLETE_RESUMPTION_TICKET_VALIDATION.Result); break; + case QUIC_API_TYPE_CONN_COMPLETE_CERTIFICATE_VALIDATION: + CXPLAT_DBG_ASSERT(QuicConnIsClient(Connection)); + QuicCryptoCustomCertValidationComplete( + &Connection->Crypto, + ApiCtx->CONN_COMPLETE_CERTIFICATE_VALIDATION.Result); + break; + case QUIC_API_TYPE_STRM_CLOSE: QuicStreamClose(ApiCtx->STRM_CLOSE.Stream); break; diff --git a/src/core/library.c b/src/core/library.c index 4765ef769..f89264253 100644 --- a/src/core/library.c +++ b/src/core/library.c @@ -1669,6 +1669,7 @@ MsQuicOpenVersion( Api->ConnectionSetConfiguration = MsQuicConnectionSetConfiguration; Api->ConnectionSendResumptionTicket = MsQuicConnectionSendResumptionTicket; Api->ConnectionResumptionTicketValidationComplete = MsQuicConnectionResumptionTicketValidationComplete; + Api->ConnectionCertificateValidationComplete = MsQuicConnectionCertificateValidationComplete; Api->StreamOpen = MsQuicStreamOpen; Api->StreamClose = MsQuicStreamClose; diff --git a/src/core/operation.h b/src/core/operation.h index 93fceac8e..6d717cd71 100644 --- a/src/core/operation.h +++ b/src/core/operation.h @@ -62,6 +62,7 @@ typedef enum QUIC_API_TYPE { QUIC_API_TYPE_DATAGRAM_SEND, QUIC_API_TYPE_CONN_COMPLETE_RESUMPTION_TICKET_VALIDATION, + QUIC_API_TYPE_CONN_COMPLETE_CERTIFICATE_VALIDATION, } QUIC_API_TYPE; @@ -119,6 +120,10 @@ typedef struct QUIC_API_CONTEXT { BOOLEAN Result; } CONN_COMPLETE_RESUMPTION_TICKET_VALIDATION; + struct { + BOOLEAN Result; + } CONN_COMPLETE_CERTIFICATE_VALIDATION; + struct { QUIC_STREAM_OPEN_FLAGS Flags; QUIC_STREAM_CALLBACK_HANDLER Handler; diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs index 2666d1e72..bb4d55d16 100644 --- a/src/cs/lib/msquic_generated.cs +++ b/src/cs/lib/msquic_generated.cs @@ -2755,6 +2755,9 @@ namespace Microsoft.Quic [NativeTypeName("QUIC_CONNECTION_COMP_RESUMPTION_FN")] internal delegate* unmanaged[Cdecl] ConnectionResumptionTicketValidationComplete; + + [NativeTypeName("QUIC_CONNECTION_COMP_CERT_FN")] + internal delegate* unmanaged[Cdecl] ConnectionCertificateValidationComplete; } internal static unsafe partial class MsQuic diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 836ccd146..26fe47830 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -1279,6 +1279,19 @@ QUIC_STATUS _In_ BOOLEAN Result ); +// +// Uses the QUIC (client) handle to complete certificate validation. +// This must be called after client app handles certificate validation +// and then return QUIC_STATUS_PENDING. +// +typedef +_IRQL_requires_max_(DISPATCH_LEVEL) +QUIC_STATUS +(QUIC_API * QUIC_CONNECTION_COMP_CERT_FN)( + _In_ _Pre_defensive_ HQUIC Connection, + _In_ BOOLEAN Result + ); + // // Streams // @@ -1507,6 +1520,7 @@ typedef struct QUIC_API_TABLE { QUIC_DATAGRAM_SEND_FN DatagramSend; QUIC_CONNECTION_COMP_RESUMPTION_FN ConnectionResumptionTicketValidationComplete; // Available from v2.2 + QUIC_CONNECTION_COMP_CERT_FN ConnectionCertificateValidationComplete; // Available from v2.2 } QUIC_API_TABLE; diff --git a/src/inc/quic_trace.h b/src/inc/quic_trace.h index 71b1fc053..a77dabfac 100644 --- a/src/inc/quic_trace.h +++ b/src/inc/quic_trace.h @@ -89,6 +89,7 @@ typedef enum QUIC_TRACE_API_TYPE { QUIC_TRACE_API_CONNECTION_SET_CONFIGURATION, QUIC_TRACE_API_CONNECTION_SEND_RESUMPTION_TICKET, QUIC_TRACE_API_CONNECTION_COMPLETE_RESUMPTION_TICKET_VALIDATION, + QUIC_TRACE_API_CONNECTION_COMPLETE_CERTIFICATE_VALIDATION, QUIC_TRACE_API_STREAM_OPEN, QUIC_TRACE_API_STREAM_CLOSE, QUIC_TRACE_API_STREAM_START, diff --git a/src/lib.rs b/src/lib.rs index 07508de45..d220748b9 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -1082,6 +1082,10 @@ struct ApiTable { connection: Handle, result: BOOLEAN, ) -> u32, + certificate_validation_complete: extern "C" fn( + connection: Handle, + result: BOOLEAN, + ) -> u32, } #[link(name = "msquic")] @@ -1538,6 +1542,21 @@ impl Connection { panic!("ticket validation completion failure 0x{:x}", status); } } + + pub fn certificate_validation_complete( + &self, + result: BOOLEAN, + ) { + let status = unsafe { + ((*self.table).certificate_validation_complete)( + self.handle, + result, + ) + }; + if Status::failed(status) { + panic!("ticket validation completion failure 0x{:x}", status); + } + } } impl Drop for Connection { diff --git a/src/plugins/dbg/quictypes.h b/src/plugins/dbg/quictypes.h index 058e31a62..d838fc336 100644 --- a/src/plugins/dbg/quictypes.h +++ b/src/plugins/dbg/quictypes.h @@ -993,6 +993,7 @@ typedef enum QUIC_API_TYPE { QUIC_API_TYPE_DATAGRAM_SEND, QUIC_API_TYPE_CONN_COMPLETE_RESUMPTION_TICKET_VALIDATION, + QUIC_API_TYPE_CONN_COMPLETE_CERTIFICATE_VALIDATION, } QUIC_API_TYPE; @@ -1036,6 +1037,8 @@ struct ApiCall : Struct { return "API_TYPE_DATAGRAM_SEND"; case QUIC_API_TYPE_CONN_COMPLETE_RESUMPTION_TICKET_VALIDATION: return "API_TYPE_CONN_COMPLETE_RESUMPTION_TICKET_VALIDATION"; + case QUIC_API_TYPE_CONN_COMPLETE_CERTIFICATE_VALIDATION: + return "API_TYPE_CONN_COMPLETE_CERTIFICATE_VALIDATION"; default: return "INVALID API"; } diff --git a/src/test/lib/TestConnection.cpp b/src/test/lib/TestConnection.cpp index c9715eaf4..f14b1fc75 100644 --- a/src/test/lib/TestConnection.cpp +++ b/src/test/lib/TestConnection.cpp @@ -751,11 +751,9 @@ TestConnection::SetCustomValidationResult( { BOOLEAN Result = AcceptCert ? TRUE : FALSE; return - MsQuic->SetParam( + MsQuic->ConnectionCertificateValidationComplete( QuicConnection, - QUIC_PARAM_CONN_PEER_CERTIFICATE_VALID, - sizeof(Result), - &Result); + Result); } QUIC_STATUS diff --git a/src/tools/spin/spinquic.cpp b/src/tools/spin/spinquic.cpp index 001adb12f..12b528573 100644 --- a/src/tools/spin/spinquic.cpp +++ b/src/tools/spin/spinquic.cpp @@ -258,6 +258,7 @@ typedef enum { SpinQuicAPICallGetParamStream, SpinQuicAPICallDatagramSend, SpinQuicAPICallCompleteTicketValidation, + SpinQuicAPICallCompleteCertificateValidation, SpinQuicAPICallStreamReceiveSetEnabled, SpinQuicAPICallStreamReceiveComplete, SpinQuicAPICallCount // Always the last element @@ -881,6 +882,12 @@ void Spin(Gbs& Gb, LockableVector& Connections, std::vector* Liste MsQuic.ConnectionResumptionTicketValidationComplete(Connection, GetRandom(2) == 0); break; } + case SpinQuicAPICallCompleteCertificateValidation: { + auto Connection = Connections.TryGetRandom(); + BAIL_ON_NULL_CONNECTION(Connection); + MsQuic.ConnectionCertificateValidationComplete(Connection, GetRandom(2) == 0); + break; + } default: break; }