From c5de3995a666778fc58dd90aaa9194bcd458db2b Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sun, 28 Sep 2025 13:44:27 -0400 Subject: [PATCH 1/5] librustls: replace u32_enum_builder macro We only used this for `rustls_result`, and in practice it only saved us having to implement `From` by hand. That's handy, but comes at the cost of needing to use the nightly toolchain w/ cbindgen so it can expand the macro before generating the `.h`. That wasn't the worst, but a nighty regression that has remained unfixed for months broke this workflow. In sum: life will be easier without the macro. RIP. --- librustls/src/error.rs | 489 +++++++++++++++++++++++++---------------- 1 file changed, 299 insertions(+), 190 deletions(-) diff --git a/librustls/src/error.rs b/librustls/src/error.rs index 333525dc..db730cdd 100644 --- a/librustls/src/error.rs +++ b/librustls/src/error.rs @@ -20,198 +20,307 @@ use crate::panic::ffi_panic_boundary; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct rustls_io_result(pub libc::c_int); -macro_rules! u32_enum_builder { - ( - $(#[$comment:meta])* - EnumName: $enum_name: ident; - EnumDefault: $enum_default: ident; - EnumVal { $( $enum_var: ident => $enum_val: expr ),* } - ) => { - $(#[$comment])* - #[allow(dead_code)] - #[repr(u32)] - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum $enum_name { - $( $enum_var = $enum_val),* - } - impl From for $enum_name { - fn from(x: u32) -> Self { - match x { - $($enum_val => $enum_name::$enum_var),* - , _ => $enum_name::$enum_default, - } - } - } - }; +/// Numeric error codes returned from rustls-ffi API functions. +#[allow(dead_code)] +#[repr(u32)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum rustls_result { + Ok = 7000, + Io = 7001, + NullParameter = 7002, + InvalidDnsNameError = 7003, + Panic = 7004, + CertificateParseError = 7005, + PrivateKeyParseError = 7006, + InsufficientSize = 7007, + NotFound = 7008, + InvalidParameter = 7009, + UnexpectedEof = 7010, + PlaintextEmpty = 7011, + AcceptorNotReady = 7012, + AlreadyUsed = 7013, + CertificateRevocationListParseError = 7014, + NoServerCertVerifier = 7015, + NoDefaultCryptoProvider = 7016, + GetRandomFailed = 7017, + NoCertResolver = 7018, + HpkeError = 7019, + BuilderIncompatibleTlsVersions = 7020, + + // From https://docs.rs/rustls/latest/rustls/enum.Error.html + NoCertificatesPresented = 7101, + DecryptError = 7102, + FailedToGetCurrentTime = 7103, + FailedToGetRandomBytes = 7113, + HandshakeNotComplete = 7104, + PeerSentOversizedRecord = 7105, + NoApplicationProtocol = 7106, + BadMaxFragmentSize = 7114, + UnsupportedNameType = 7115, + EncryptError = 7116, + + // Reserved from previous use pre rustls-ffi <0.21.0 + // CorruptMessage => 7100, + // CorruptMessagePayload => 7111, + // CertInvalidEncoding => 7117, + // CertInvalidSignatureType => 7118, + // CertInvalidSignature => 7119, + // CertInvalidData => 7120, + + // From InvalidCertificate, with fields that get flattened. + // https://docs.rs/rustls/0.21.0/rustls/enum.Error.html#variant.InvalidCertificate + CertEncodingBad = 7121, + CertExpired = 7122, + CertNotYetValid = 7123, + CertRevoked = 7124, + CertUnhandledCriticalExtension = 7125, + CertUnknownIssuer = 7126, + CertBadSignature = 7127, + CertNotValidForName = 7128, + CertInvalidPurpose = 7129, + CertApplicationVerificationFailure = 7130, + CertOtherError = 7131, + CertUnknownRevocationStatus = 7154, + CertExpiredRevocationList = 7156, + CertUnsupportedSignatureAlgorithm = 7157, // Last added. + + // From InvalidMessage, with fields that get flattened. + // https://docs.rs/rustls/0.21.0/rustls/enum.Error.html#variant.InvalidMessage + MessageHandshakePayloadTooLarge = 7133, + MessageInvalidCcs = 7134, + MessageInvalidContentType = 7135, + MessageInvalidCertStatusType = 7136, + MessageInvalidCertRequest = 7137, + MessageInvalidDhParams = 7138, + MessageInvalidEmptyPayload = 7139, + MessageInvalidKeyUpdate = 7140, + MessageInvalidServerName = 7141, + MessageTooLarge = 7142, + MessageTooShort = 7143, + MessageMissingData = 7144, + MessageMissingKeyExchange = 7145, + MessageNoSignatureSchemes = 7146, + MessageTrailingData = 7147, + MessageUnexpectedMessage = 7148, + MessageUnknownProtocolVersion = 7149, + MessageUnsupportedCompression = 7150, + MessageUnsupportedCurveType = 7151, + MessageUnsupportedKeyExchangeAlgorithm = 7152, + MessageInvalidOther = 7153, + MessageCertificatePayloadTooLarge = 7155, + + // From Error, with fields that get dropped. + PeerIncompatibleError = 7107, + PeerMisbehavedError = 7108, + InappropriateMessage = 7109, + InappropriateHandshakeMessage = 7110, + General = 7112, + + // From Error, with fields that get flattened. + // https://docs.rs/rustls/latest/rustls/internal/msgs/enums/enum.AlertDescription.html + AlertCloseNotify = 7200, + AlertUnexpectedMessage = 7201, + AlertBadRecordMac = 7202, + AlertDecryptionFailed = 7203, + AlertRecordOverflow = 7204, + AlertDecompressionFailure = 7205, + AlertHandshakeFailure = 7206, + AlertNoCertificate = 7207, + AlertBadCertificate = 7208, + AlertUnsupportedCertificate = 7209, + AlertCertificateRevoked = 7210, + AlertCertificateExpired = 7211, + AlertCertificateUnknown = 7212, + AlertIllegalParameter = 7213, + AlertUnknownCA = 7214, + AlertAccessDenied = 7215, + AlertDecodeError = 7216, + AlertDecryptError = 7217, + AlertExportRestriction = 7218, + AlertProtocolVersion = 7219, + AlertInsufficientSecurity = 7220, + AlertInternalError = 7221, + AlertInappropriateFallback = 7222, + AlertUserCanceled = 7223, + AlertNoRenegotiation = 7224, + AlertMissingExtension = 7225, + AlertUnsupportedExtension = 7226, + AlertCertificateUnobtainable = 7227, + AlertUnrecognisedName = 7228, + AlertBadCertificateStatusResponse = 7229, + AlertBadCertificateHashValue = 7230, + AlertUnknownPSKIdentity = 7231, + AlertCertificateRequired = 7232, + AlertNoApplicationProtocol = 7233, + AlertUnknown = 7234, + + // Reserved from previous use pre rustls-ffi <0.22.0 + // CertSCTMalformed => 7319, + // CertSCTInvalidSignature => 7320, + // CertSCTTimestampInFuture => 7321, + // CertSCTUnsupportedVersion => 7322, + // CertSCTUnknownLog => 7323, + + // From InvalidCertRevocationList, with fields that get flattened. + // https://docs.rs/rustls/0.21.6/rustls/enum.Error.html#variant.InvalidCertRevocationList + CertRevocationListBadSignature = 7400, + CertRevocationListInvalidCrlNumber = 7401, + CertRevocationListInvalidRevokedCertSerialNumber = 7402, + CertRevocationListIssuerInvalidForCrl = 7403, + CertRevocationListOtherError = 7404, + CertRevocationListParseError = 7405, + CertRevocationListUnsupportedCrlVersion = 7406, + CertRevocationListUnsupportedCriticalExtension = 7407, + CertRevocationListUnsupportedDeltaCrl = 7408, + CertRevocationListUnsupportedIndirectCrl = 7409, + CertRevocationListUnsupportedRevocationReason = 7410, + CertRevocationListUnsupportedSignatureAlgorithm = 7411, + + // From ClientCertVerifierBuilderError, with fields that get flattened. + ClientCertVerifierBuilderNoRootAnchors = 7500, + + // From InconsistentKeys, with fields that get flattened. + InconsistentKeysKeysMismatch = 7600, + InconsistentKeysUnknown = 7601, + + // From InvalidEncryptedClientHello, with fields that get flattened. + InvalidEncryptedClientHelloInvalidConfigList = 7700, + InvalidEncryptedClientHelloNoCompatibleConfig = 7701, + InvalidEncryptedClientHelloSniRequired = 7702, } -u32_enum_builder! { - /// Numeric error codes returned from rustls-ffi API functions. - EnumName: rustls_result; - EnumDefault: InvalidParameter; - EnumVal{ - Ok => 7000, - Io => 7001, - NullParameter => 7002, - InvalidDnsNameError => 7003, - Panic => 7004, - CertificateParseError => 7005, - PrivateKeyParseError => 7006, - InsufficientSize => 7007, - NotFound => 7008, - InvalidParameter => 7009, - UnexpectedEof => 7010, - PlaintextEmpty => 7011, - AcceptorNotReady => 7012, - AlreadyUsed => 7013, - CertificateRevocationListParseError => 7014, - NoServerCertVerifier => 7015, - NoDefaultCryptoProvider => 7016, - GetRandomFailed => 7017, - NoCertResolver => 7018, - HpkeError => 7019, - BuilderIncompatibleTlsVersions => 7020, - - // From https://docs.rs/rustls/latest/rustls/enum.Error.html - NoCertificatesPresented => 7101, - DecryptError => 7102, - FailedToGetCurrentTime => 7103, - FailedToGetRandomBytes => 7113, - HandshakeNotComplete => 7104, - PeerSentOversizedRecord => 7105, - NoApplicationProtocol => 7106, - BadMaxFragmentSize => 7114, - UnsupportedNameType => 7115, - EncryptError => 7116, - - // Reserved from previous use pre rustls-ffi <0.21.0 - // CorruptMessage => 7100, - // CorruptMessagePayload => 7111, - // CertInvalidEncoding => 7117, - // CertInvalidSignatureType => 7118, - // CertInvalidSignature => 7119, - // CertInvalidData => 7120, - - // From InvalidCertificate, with fields that get flattened. - // https://docs.rs/rustls/0.21.0/rustls/enum.Error.html#variant.InvalidCertificate - CertEncodingBad => 7121, - CertExpired => 7122, - CertNotYetValid => 7123, - CertRevoked => 7124, - CertUnhandledCriticalExtension => 7125, - CertUnknownIssuer => 7126, - CertBadSignature => 7127, - CertNotValidForName => 7128, - CertInvalidPurpose => 7129, - CertApplicationVerificationFailure => 7130, - CertOtherError => 7131, - CertUnknownRevocationStatus => 7154, - CertExpiredRevocationList => 7156, - CertUnsupportedSignatureAlgorithm => 7157, // Last added. - - // From InvalidMessage, with fields that get flattened. - // https://docs.rs/rustls/0.21.0/rustls/enum.Error.html#variant.InvalidMessage - MessageHandshakePayloadTooLarge => 7133, - MessageInvalidCcs => 7134, - MessageInvalidContentType => 7135, - MessageInvalidCertStatusType => 7136, - MessageInvalidCertRequest => 7137, - MessageInvalidDhParams => 7138, - MessageInvalidEmptyPayload => 7139, - MessageInvalidKeyUpdate => 7140, - MessageInvalidServerName => 7141, - MessageTooLarge => 7142, - MessageTooShort => 7143, - MessageMissingData => 7144, - MessageMissingKeyExchange => 7145, - MessageNoSignatureSchemes => 7146, - MessageTrailingData => 7147, - MessageUnexpectedMessage => 7148, - MessageUnknownProtocolVersion => 7149, - MessageUnsupportedCompression => 7150, - MessageUnsupportedCurveType => 7151, - MessageUnsupportedKeyExchangeAlgorithm => 7152, - MessageInvalidOther => 7153, - MessageCertificatePayloadTooLarge => 7155, - - // From Error, with fields that get dropped. - PeerIncompatibleError => 7107, - PeerMisbehavedError => 7108, - InappropriateMessage => 7109, - InappropriateHandshakeMessage => 7110, - General => 7112, - - // From Error, with fields that get flattened. - // https://docs.rs/rustls/latest/rustls/internal/msgs/enums/enum.AlertDescription.html - AlertCloseNotify => 7200, - AlertUnexpectedMessage => 7201, - AlertBadRecordMac => 7202, - AlertDecryptionFailed => 7203, - AlertRecordOverflow => 7204, - AlertDecompressionFailure => 7205, - AlertHandshakeFailure => 7206, - AlertNoCertificate => 7207, - AlertBadCertificate => 7208, - AlertUnsupportedCertificate => 7209, - AlertCertificateRevoked => 7210, - AlertCertificateExpired => 7211, - AlertCertificateUnknown => 7212, - AlertIllegalParameter => 7213, - AlertUnknownCA => 7214, - AlertAccessDenied => 7215, - AlertDecodeError => 7216, - AlertDecryptError => 7217, - AlertExportRestriction => 7218, - AlertProtocolVersion => 7219, - AlertInsufficientSecurity => 7220, - AlertInternalError => 7221, - AlertInappropriateFallback => 7222, - AlertUserCanceled => 7223, - AlertNoRenegotiation => 7224, - AlertMissingExtension => 7225, - AlertUnsupportedExtension => 7226, - AlertCertificateUnobtainable => 7227, - AlertUnrecognisedName => 7228, - AlertBadCertificateStatusResponse => 7229, - AlertBadCertificateHashValue => 7230, - AlertUnknownPSKIdentity => 7231, - AlertCertificateRequired => 7232, - AlertNoApplicationProtocol => 7233, - AlertUnknown => 7234, - - // Reserved from previous use pre rustls-ffi <0.22.0 - // CertSCTMalformed => 7319, - // CertSCTInvalidSignature => 7320, - // CertSCTTimestampInFuture => 7321, - // CertSCTUnsupportedVersion => 7322, - // CertSCTUnknownLog => 7323, - - // From InvalidCertRevocationList, with fields that get flattened. - // https://docs.rs/rustls/0.21.6/rustls/enum.Error.html#variant.InvalidCertRevocationList - CertRevocationListBadSignature => 7400, - CertRevocationListInvalidCrlNumber => 7401, - CertRevocationListInvalidRevokedCertSerialNumber => 7402, - CertRevocationListIssuerInvalidForCrl => 7403, - CertRevocationListOtherError => 7404, - CertRevocationListParseError => 7405, - CertRevocationListUnsupportedCrlVersion => 7406, - CertRevocationListUnsupportedCriticalExtension => 7407, - CertRevocationListUnsupportedDeltaCrl => 7408, - CertRevocationListUnsupportedIndirectCrl => 7409, - CertRevocationListUnsupportedRevocationReason => 7410, - CertRevocationListUnsupportedSignatureAlgorithm => 7411, - - // From ClientCertVerifierBuilderError, with fields that get flattened. - ClientCertVerifierBuilderNoRootAnchors => 7500, - - // From InconsistentKeys, with fields that get flattened. - InconsistentKeysKeysMismatch => 7600, - InconsistentKeysUnknown => 7601, - - // From InvalidEncryptedClientHello, with fields that get flattened. - InvalidEncryptedClientHelloInvalidConfigList => 7700, - InvalidEncryptedClientHelloNoCompatibleConfig => 7701, - InvalidEncryptedClientHelloSniRequired => 7702 +impl From for rustls_result { + fn from(x: u32) -> Self { + use rustls_result::*; + + match x { + 7000 => Ok, + 7001 => Io, + 7002 => NullParameter, + 7003 => InvalidDnsNameError, + 7004 => Panic, + 7005 => CertificateParseError, + 7006 => PrivateKeyParseError, + 7007 => InsufficientSize, + 7008 => NotFound, + 7009 => InvalidParameter, + 7010 => UnexpectedEof, + 7011 => PlaintextEmpty, + 7012 => AcceptorNotReady, + 7013 => AlreadyUsed, + 7014 => CertificateRevocationListParseError, + 7015 => NoServerCertVerifier, + 7016 => NoDefaultCryptoProvider, + 7017 => GetRandomFailed, + 7018 => NoCertResolver, + 7019 => HpkeError, + 7020 => BuilderIncompatibleTlsVersions, + 7101 => NoCertificatesPresented, + 7102 => DecryptError, + 7103 => FailedToGetCurrentTime, + 7113 => FailedToGetRandomBytes, + 7104 => HandshakeNotComplete, + 7105 => PeerSentOversizedRecord, + 7106 => NoApplicationProtocol, + 7114 => BadMaxFragmentSize, + 7115 => UnsupportedNameType, + 7116 => EncryptError, + 7121 => CertEncodingBad, + 7122 => CertExpired, + 7123 => CertNotYetValid, + 7124 => CertRevoked, + 7125 => CertUnhandledCriticalExtension, + 7126 => CertUnknownIssuer, + 7127 => CertBadSignature, + 7128 => CertNotValidForName, + 7129 => CertInvalidPurpose, + 7130 => CertApplicationVerificationFailure, + 7131 => CertOtherError, + 7154 => CertUnknownRevocationStatus, + 7156 => CertExpiredRevocationList, + 7157 => CertUnsupportedSignatureAlgorithm, + 7133 => MessageHandshakePayloadTooLarge, + 7134 => MessageInvalidCcs, + 7135 => MessageInvalidContentType, + 7136 => MessageInvalidCertStatusType, + 7137 => MessageInvalidCertRequest, + 7138 => MessageInvalidDhParams, + 7139 => MessageInvalidEmptyPayload, + 7140 => MessageInvalidKeyUpdate, + 7141 => MessageInvalidServerName, + 7142 => MessageTooLarge, + 7143 => MessageTooShort, + 7144 => MessageMissingData, + 7145 => MessageMissingKeyExchange, + 7146 => MessageNoSignatureSchemes, + 7147 => MessageTrailingData, + 7148 => MessageUnexpectedMessage, + 7149 => MessageUnknownProtocolVersion, + 7150 => MessageUnsupportedCompression, + 7151 => MessageUnsupportedCurveType, + 7152 => MessageUnsupportedKeyExchangeAlgorithm, + 7153 => MessageInvalidOther, + 7155 => MessageCertificatePayloadTooLarge, + 7107 => PeerIncompatibleError, + 7108 => PeerMisbehavedError, + 7109 => InappropriateMessage, + 7110 => InappropriateHandshakeMessage, + 7112 => General, + 7200 => AlertCloseNotify, + 7201 => AlertUnexpectedMessage, + 7202 => AlertBadRecordMac, + 7203 => AlertDecryptionFailed, + 7204 => AlertRecordOverflow, + 7205 => AlertDecompressionFailure, + 7206 => AlertHandshakeFailure, + 7207 => AlertNoCertificate, + 7208 => AlertBadCertificate, + 7209 => AlertUnsupportedCertificate, + 7210 => AlertCertificateRevoked, + 7211 => AlertCertificateExpired, + 7212 => AlertCertificateUnknown, + 7213 => AlertIllegalParameter, + 7214 => AlertUnknownCA, + 7215 => AlertAccessDenied, + 7216 => AlertDecodeError, + 7217 => AlertDecryptError, + 7218 => AlertExportRestriction, + 7219 => AlertProtocolVersion, + 7220 => AlertInsufficientSecurity, + 7221 => AlertInternalError, + 7222 => AlertInappropriateFallback, + 7223 => AlertUserCanceled, + 7224 => AlertNoRenegotiation, + 7225 => AlertMissingExtension, + 7226 => AlertUnsupportedExtension, + 7227 => AlertCertificateUnobtainable, + 7228 => AlertUnrecognisedName, + 7229 => AlertBadCertificateStatusResponse, + 7230 => AlertBadCertificateHashValue, + 7231 => AlertUnknownPSKIdentity, + 7232 => AlertCertificateRequired, + 7233 => AlertNoApplicationProtocol, + 7234 => AlertUnknown, + 7400 => CertRevocationListBadSignature, + 7401 => CertRevocationListInvalidCrlNumber, + 7402 => CertRevocationListInvalidRevokedCertSerialNumber, + 7403 => CertRevocationListIssuerInvalidForCrl, + 7404 => CertRevocationListOtherError, + 7405 => CertRevocationListParseError, + 7406 => CertRevocationListUnsupportedCrlVersion, + 7407 => CertRevocationListUnsupportedCriticalExtension, + 7408 => CertRevocationListUnsupportedDeltaCrl, + 7409 => CertRevocationListUnsupportedIndirectCrl, + 7410 => CertRevocationListUnsupportedRevocationReason, + 7411 => CertRevocationListUnsupportedSignatureAlgorithm, + 7500 => ClientCertVerifierBuilderNoRootAnchors, + 7600 => InconsistentKeysKeysMismatch, + 7601 => InconsistentKeysUnknown, + 7700 => InvalidEncryptedClientHelloInvalidConfigList, + 7701 => InvalidEncryptedClientHelloNoCompatibleConfig, + 7702 => InvalidEncryptedClientHelloSniRequired, + _ => InvalidParameter, + } } } From 42d81bb3d2b7b0a9b046832dc11defd68e4f97b2 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sun, 28 Sep 2025 14:14:09 -0400 Subject: [PATCH 2/5] librustls: replace castable macros They're helpful, but require us to use cbindgen's parse.expand feature which in turn requires nightly, and is broken with nightly since ~April. --- librustls/src/acceptor.rs | 93 +++++++++++++++----------- librustls/src/certificate.rs | 71 +++++++++++++------- librustls/src/cipher.rs | 13 ++-- librustls/src/client.rs | 52 +++++++++------ librustls/src/connection.rs | 13 ++-- librustls/src/crypto_provider.rs | 60 +++++++++++------ librustls/src/ffi.rs | 94 --------------------------- librustls/src/server.rs | 52 +++++++++------ librustls/src/verifier.rs | 108 ++++++++++++++++++------------- 9 files changed, 284 insertions(+), 272 deletions(-) diff --git a/librustls/src/acceptor.rs b/librustls/src/acceptor.rs index 1c609c9b..bc4504c7 100644 --- a/librustls/src/acceptor.rs +++ b/librustls/src/acceptor.rs @@ -4,7 +4,7 @@ use rustls::server::{Accepted, AcceptedAlert, Acceptor}; use crate::connection::rustls_connection; use crate::error::{map_error, rustls_io_result, rustls_result}; use crate::ffi::{ - box_castable, free_box, set_boxed_mut_ptr, to_box, to_boxed_mut_ptr, try_callback, + Castable, OwnershipBox, free_box, set_boxed_mut_ptr, to_box, to_boxed_mut_ptr, try_callback, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr, try_take, }; use crate::io::{CallbackReader, CallbackWriter, rustls_read_callback, rustls_write_callback}; @@ -12,43 +12,53 @@ use crate::panic::ffi_panic_boundary; use crate::rslice::{rustls_slice_bytes, rustls_str}; use crate::server::rustls_server_config; -box_castable! { - /// A buffer and parser for ClientHello bytes. - /// - /// This allows reading ClientHello before choosing a rustls_server_config. - /// - /// It's useful when the server config will be based on parameters in the - /// ClientHello: server name indication (SNI), ALPN protocols, signature - /// schemes, and cipher suites. - /// - /// In particular, if a server wants to do some potentially expensive work - /// to load a certificate for a given hostname, rustls_acceptor allows doing - /// that asynchronously, as opposed to rustls_server_config_builder_set_hello_callback(), - /// which doesn't work well for asynchronous I/O. - /// - /// The general flow is: - /// - rustls_acceptor_new() - /// - Loop: - /// - Read bytes from the network it with rustls_acceptor_read_tls(). - /// - If successful, parse those bytes with rustls_acceptor_accept(). - /// - If that returns RUSTLS_RESULT_ACCEPTOR_NOT_READY, continue. - /// - Otherwise, break. - /// - If rustls_acceptor_accept() returned RUSTLS_RESULT_OK: - /// - Examine the resulting rustls_accepted. - /// - Create or select a rustls_server_config. - /// - Call rustls_accepted_into_connection(). - /// - Otherwise, there was a problem with the ClientHello data and the - /// connection should be rejected. - pub struct rustls_acceptor(Acceptor); +/// A buffer and parser for ClientHello bytes. +/// +/// This allows reading ClientHello before choosing a rustls_server_config. +/// +/// It's useful when the server config will be based on parameters in the +/// ClientHello: server name indication (SNI), ALPN protocols, signature +/// schemes, and cipher suites. +/// +/// In particular, if a server wants to do some potentially expensive work +/// to load a certificate for a given hostname, rustls_acceptor allows doing +/// that asynchronously, as opposed to rustls_server_config_builder_set_hello_callback(), +/// which doesn't work well for asynchronous I/O. +/// +/// The general flow is: +/// - rustls_acceptor_new() +/// - Loop: +/// - Read bytes from the network it with rustls_acceptor_read_tls(). +/// - If successful, parse those bytes with rustls_acceptor_accept(). +/// - If that returns RUSTLS_RESULT_ACCEPTOR_NOT_READY, continue. +/// - Otherwise, break. +/// - If rustls_acceptor_accept() returned RUSTLS_RESULT_OK: +/// - Examine the resulting rustls_accepted. +/// - Create or select a rustls_server_config. +/// - Call rustls_accepted_into_connection(). +/// - Otherwise, there was a problem with the ClientHello data and the +/// connection should be rejected. +pub struct rustls_acceptor { + _private: [u8; 0], } -box_castable! { - /// A parsed ClientHello produced by a rustls_acceptor. - /// - /// It is used to check server name indication (SNI), ALPN protocols, - /// signature schemes, and cipher suites. It can be combined with a - /// `rustls_server_config` to build a `rustls_connection`. - pub struct rustls_accepted(Option); +impl Castable for rustls_acceptor { + type Ownership = OwnershipBox; + type RustType = Acceptor; +} + +/// A parsed ClientHello produced by a rustls_acceptor. +/// +/// It is used to check server name indication (SNI), ALPN protocols, +/// signature schemes, and cipher suites. It can be combined with a +/// `rustls_server_config` to build a `rustls_connection`. +pub struct rustls_accepted { + _private: [u8; 0], +} + +impl Castable for rustls_accepted { + type Ownership = OwnershipBox; + type RustType = Option; } impl rustls_acceptor { @@ -446,9 +456,14 @@ impl rustls_accepted { } } -box_castable! { - /// Represents a TLS alert resulting from accepting a client. - pub struct rustls_accepted_alert(AcceptedAlert); +/// Represents a TLS alert resulting from accepting a client. +pub struct rustls_accepted_alert { + _private: [u8; 0], +} + +impl Castable for rustls_accepted_alert { + type Ownership = OwnershipBox; + type RustType = AcceptedAlert; } impl rustls_accepted_alert { diff --git a/librustls/src/certificate.rs b/librustls/src/certificate.rs index 1f76e783..0e164423 100644 --- a/librustls/src/certificate.rs +++ b/librustls/src/certificate.rs @@ -12,18 +12,24 @@ use rustls::sign::CertifiedKey; use crate::crypto_provider::{self, rustls_signing_key}; use crate::error::{map_error, rustls_result}; use crate::ffi::{ - arc_castable, box_castable, free_arc, free_box, ref_castable, set_arc_mut_ptr, + Castable, OwnershipArc, OwnershipBox, OwnershipRef, free_arc, free_box, set_arc_mut_ptr, to_arc_const_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_mut_from_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, try_take, }; use crate::panic::ffi_panic_boundary; use crate::rslice::rustls_slice_bytes; -ref_castable! { - /// An X.509 certificate, as used in rustls. - /// Corresponds to `CertificateDer` in the Rust pki-types API. - /// - pub struct rustls_certificate(CertificateDer<'a>); +/// An X.509 certificate, as used in rustls. +/// Corresponds to `CertificateDer` in the Rust pki-types API. +/// +pub struct rustls_certificate<'a> { + _private: [u8; 0], + _marker: PhantomData<&'a ()>, +} + +impl<'a> Castable for rustls_certificate<'a> { + type Ownership = OwnershipRef; + type RustType = CertificateDer<'a>; } /// Get the DER data of the certificate itself. @@ -48,13 +54,18 @@ pub extern "C" fn rustls_certificate_get_der( } } -arc_castable! { - /// The complete chain of certificates to send during a TLS handshake, - /// plus a private key that matches the end-entity (leaf) certificate. - /// - /// Corresponds to `CertifiedKey` in the Rust API. - /// - pub struct rustls_certified_key(CertifiedKey); +/// The complete chain of certificates to send during a TLS handshake, +/// plus a private key that matches the end-entity (leaf) certificate. +/// +/// Corresponds to `CertifiedKey` in the Rust API. +/// +pub struct rustls_certified_key { + _private: [u8; 0], +} + +impl Castable for rustls_certified_key { + type Ownership = OwnershipArc; + type RustType = CertifiedKey; } impl rustls_certified_key { @@ -270,14 +281,19 @@ impl rustls_certified_key { } } -box_castable! { - /// A `rustls_root_cert_store` being constructed. - /// - /// A builder can be modified by adding trust anchor root certificates with - /// `rustls_root_cert_store_builder_add_pem`. Once you're done adding root certificates, - /// call `rustls_root_cert_store_builder_build` to turn it into a `rustls_root_cert_store`. - /// This object is not safe for concurrent mutation. - pub struct rustls_root_cert_store_builder(Option); +/// A `rustls_root_cert_store` being constructed. +/// +/// A builder can be modified by adding trust anchor root certificates with +/// `rustls_root_cert_store_builder_add_pem`. Once you're done adding root certificates, +/// call `rustls_root_cert_store_builder_build` to turn it into a `rustls_root_cert_store`. +/// This object is not safe for concurrent mutation. +pub struct rustls_root_cert_store_builder { + _private: [u8; 0], +} + +impl Castable for rustls_root_cert_store_builder { + type Ownership = OwnershipBox; + type RustType = Option; } pub(crate) struct RootCertStoreBuilder { @@ -440,10 +456,15 @@ impl rustls_root_cert_store_builder { } } -arc_castable! { - /// A root certificate store. - /// - pub struct rustls_root_cert_store(RootCertStore); +/// A root certificate store. +/// +pub struct rustls_root_cert_store { + _private: [u8; 0], +} + +impl Castable for rustls_root_cert_store { + type Ownership = OwnershipArc; + type RustType = RootCertStore; } impl rustls_root_cert_store { diff --git a/librustls/src/cipher.rs b/librustls/src/cipher.rs index 625911ca..66526731 100644 --- a/librustls/src/cipher.rs +++ b/librustls/src/cipher.rs @@ -1,13 +1,18 @@ use rustls::SupportedCipherSuite; use crate::enums::rustls_tls_version; -use crate::ffi::{ref_castable, try_ref_from_ptr}; +use crate::ffi::{Castable, OwnershipRef, try_ref_from_ptr}; use crate::panic::ffi_panic_boundary; use crate::rslice::rustls_str; -ref_castable! { - /// A cipher suite supported by rustls. - pub struct rustls_supported_ciphersuite(SupportedCipherSuite); +/// A cipher suite supported by rustls. +pub struct rustls_supported_ciphersuite { + _private: [u8; 0], +} + +impl Castable for rustls_supported_ciphersuite { + type Ownership = OwnershipRef; + type RustType = SupportedCipherSuite; } impl rustls_supported_ciphersuite { diff --git a/librustls/src/client.rs b/librustls/src/client.rs index 8e18ae15..7a0838b8 100644 --- a/librustls/src/client.rs +++ b/librustls/src/client.rs @@ -18,7 +18,7 @@ use crate::connection::{Connection, rustls_connection}; use crate::crypto_provider::{self, rustls_crypto_provider, rustls_hpke}; use crate::error::{self, map_error, rustls_result}; use crate::ffi::{ - arc_castable, box_castable, free_arc, free_box, set_arc_mut_ptr, set_boxed_mut_ptr, + Castable, OwnershipArc, OwnershipBox, free_arc, free_box, set_arc_mut_ptr, set_boxed_mut_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, }; @@ -29,20 +29,25 @@ use crate::rslice::{rustls_slice_bytes, rustls_slice_slice_bytes, rustls_str}; use crate::userdata::userdata_get; use crate::verifier::rustls_server_cert_verifier; -box_castable! { - /// A client config being constructed. - /// - /// A builder can be modified by, e.g. `rustls_client_config_builder_load_roots_from_file`. - /// Once you're done configuring settings, call `rustls_client_config_builder_build` - /// to turn it into a *rustls_client_config. - /// - /// Alternatively, if an error occurs or, you don't wish to build a config, - /// call `rustls_client_config_builder_free` to free the builder directly. - /// - /// This object is not safe for concurrent mutation. Under the hood, - /// it corresponds to a `Box`. - /// - pub struct rustls_client_config_builder(ClientConfigBuilder); +/// A client config being constructed. +/// +/// A builder can be modified by, e.g. `rustls_client_config_builder_load_roots_from_file`. +/// Once you're done configuring settings, call `rustls_client_config_builder_build` +/// to turn it into a *rustls_client_config. +/// +/// Alternatively, if an error occurs or, you don't wish to build a config, +/// call `rustls_client_config_builder_free` to free the builder directly. +/// +/// This object is not safe for concurrent mutation. Under the hood, +/// it corresponds to a `Box`. +/// +pub struct rustls_client_config_builder { + _private: [u8; 0], +} + +impl Castable for rustls_client_config_builder { + type Ownership = OwnershipBox; + type RustType = ClientConfigBuilder; } pub(crate) struct ClientConfigBuilder { @@ -76,12 +81,17 @@ impl Default for ClientConfigBuilder { } } -arc_castable! { - /// A client config that is done being constructed and is now read-only. - /// - /// Under the hood, this object corresponds to an `Arc`. - /// - pub struct rustls_client_config(ClientConfig); +/// A client config that is done being constructed and is now read-only. +/// +/// Under the hood, this object corresponds to an `Arc`. +/// +pub struct rustls_client_config { + _private: [u8; 0], +} + +impl Castable for rustls_client_config { + type Ownership = OwnershipArc; + type RustType = ClientConfig; } impl rustls_client_config_builder { diff --git a/librustls/src/connection.rs b/librustls/src/connection.rs index 9b4dba14..c267ed75 100644 --- a/librustls/src/connection.rs +++ b/librustls/src/connection.rs @@ -11,7 +11,7 @@ use crate::certificate::rustls_certificate; use crate::enums::rustls_handshake_kind; use crate::error::{map_error, rustls_io_result, rustls_result}; use crate::ffi::{ - box_castable, free_box, try_callback, try_mut_from_ptr, try_ref_from_ptr, try_slice, + Castable, OwnershipBox, free_box, try_callback, try_mut_from_ptr, try_ref_from_ptr, try_slice, try_slice_mut, }; use crate::io::{ @@ -92,9 +92,14 @@ impl std::ops::DerefMut for Connection { } } -box_castable! { - /// A C representation of a Rustls `Connection`. - pub struct rustls_connection(Connection); +/// A C representation of a Rustls `Connection`. +pub struct rustls_connection { + _private: [u8; 0], +} + +impl Castable for rustls_connection { + type Ownership = OwnershipBox; + type RustType = Connection; } impl rustls_connection { diff --git a/librustls/src/crypto_provider.rs b/librustls/src/crypto_provider.rs index c3eced79..b45ecd08 100644 --- a/librustls/src/crypto_provider.rs +++ b/librustls/src/crypto_provider.rs @@ -16,15 +16,20 @@ use rustls::sign::SigningKey; use crate::cipher::rustls_supported_ciphersuite; use crate::error::{map_error, rustls_result}; use crate::ffi::{ - arc_castable, box_castable, free_arc, free_box, ref_castable, set_arc_mut_ptr, + Castable, OwnershipArc, OwnershipBox, OwnershipRef, free_arc, free_box, set_arc_mut_ptr, set_boxed_mut_ptr, to_boxed_mut_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, try_slice_mut, try_take, }; use crate::panic::ffi_panic_boundary; -box_castable! { - /// A `rustls_crypto_provider` builder. - pub struct rustls_crypto_provider_builder(Option); +/// A `rustls_crypto_provider` builder. +pub struct rustls_crypto_provider_builder { + _private: [u8; 0], +} + +impl Castable for rustls_crypto_provider_builder { + type Ownership = OwnershipBox; + type RustType = Option; } /// A builder for customizing a `CryptoProvider`. Can be used to install a process-wide default. @@ -284,9 +289,14 @@ pub extern "C" fn rustls_crypto_provider_default() -> *const rustls_crypto_provi } } -arc_castable! { - /// A C representation of a Rustls [`CryptoProvider`]. - pub struct rustls_crypto_provider(CryptoProvider); +/// A C representation of a Rustls [`CryptoProvider`]. +pub struct rustls_crypto_provider { + _private: [u8; 0], +} + +impl Castable for rustls_crypto_provider { + type Ownership = OwnershipArc; + type RustType = CryptoProvider; } /// Returns the number of ciphersuites the `rustls_crypto_provider` supports. @@ -471,12 +481,17 @@ pub extern "C" fn rustls_default_crypto_provider_random( } } -box_castable! { - /// A signing key that can be used to construct a certified key. - // NOTE: we box cast an arc over the dyn trait per the pattern described - // in our docs[0] for dynamically sized types. - // [0]: - pub struct rustls_signing_key(Arc); +/// A signing key that can be used to construct a certified key. +// NOTE: we box cast an arc over the dyn trait per the pattern described +// in our docs[0] for dynamically sized types. +// [0]: +pub struct rustls_signing_key { + _private: [u8; 0], +} + +impl Castable for rustls_signing_key { + type Ownership = OwnershipBox; + type RustType = Arc; } impl rustls_signing_key { @@ -490,13 +505,18 @@ impl rustls_signing_key { } } -ref_castable! { - /// A collection of supported Hybrid Public Key Encryption (HPKE) suites. - /// - /// `rustls_hpke` can be provided to `rustls_client_config_builder_enable_ech` and - /// `rustls_client_config_builder_enable_ech_grease()` to customize a - /// `rustls_client_config_builder` to use Encrypted Client Hello (ECH). - pub struct rustls_hpke(Hpke); +/// A collection of supported Hybrid Public Key Encryption (HPKE) suites. +/// +/// `rustls_hpke` can be provided to `rustls_client_config_builder_enable_ech` and +/// `rustls_client_config_builder_enable_ech_grease()` to customize a +/// `rustls_client_config_builder` to use Encrypted Client Hello (ECH). +pub struct rustls_hpke { + _private: [u8; 0], +} + +impl Castable for rustls_hpke { + type Ownership = OwnershipRef; + type RustType = Hpke; } pub(crate) struct Hpke { diff --git a/librustls/src/ffi.rs b/librustls/src/ffi.rs index 743f4566..07c72f9e 100644 --- a/librustls/src/ffi.rs +++ b/librustls/src/ffi.rs @@ -59,100 +59,6 @@ pub(crate) trait Castable { type RustType; } -/// Defines a new [`Castable`] opaque struct with [`OwnershipBox`] ownership. -/// -/// Expects to be invoked with a visibility specifier, the struct keyword, a struct name, and -/// in parens, the Rust type pointed to by raw pointers of the opaque struct's type. -/// Similar to a [newtype] with `#[repr(transparent)]`, but only allows conversions -/// between `Box` and raw pointers. -/// -/// [newtype]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction -macro_rules! box_castable { - ( - $(#[$comment:meta])* - pub struct $name:ident($rust_type:ty); - ) => { - crate::ffi::castable!(OwnershipBox $(#[$comment])* $name $rust_type); - }; -} - -pub(crate) use box_castable; - -/// Defines a new [`Castable`] opaque struct with [`OwnershipArc`] ownership. -/// -/// Expects to be invoked with a visibility specifier, the struct keyword, a struct name, and -/// in parens, the Rust type pointed to by raw pointers of the opaque struct's type. -/// Similar to a [newtype] with `#[repr(transparent)]`, but only allows conversions -/// between `Arc` and raw pointers. -/// -/// [newtype]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction -macro_rules! arc_castable { - ( - $(#[$comment:meta])* - pub struct $name:ident($rust_type:ty); - ) => { - crate::ffi::castable!(OwnershipArc $(#[$comment])* $name $rust_type); - }; -} - -pub(crate) use arc_castable; - -/// Defines a new [`Castable`] opaque struct with [`OwnershipRef`] ownership. -/// -/// Expects to be invoked with a visibility specifier, the struct keyword, a struct name, and -/// in parens, the Rust type pointed to by raw pointers of the opaque struct's type. -/// Similar to a [newtype] with `#[repr(transparent)]`, but only allows conversions -/// between a reference and raw pointers. -/// -/// If a lifetime parameter is specified, the opaque struct will be parameterized by it, -/// and a `PhantomData` field referencing the lifetime is added to the struct. -/// -/// [newtype]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction -macro_rules! ref_castable { - ( - $(#[$comment:meta])* - pub struct $name:ident ($rust_type:ident $(<$lt:tt>)?); - ) => { - $(#[$comment])* - pub struct $name $(<$lt>)? { - _private: [u8; 0], - $( _marker: PhantomData<&$lt ()>, )? - } - - impl $(<$lt>)? crate::ffi::Castable for $name $(<$lt>)? { - type Ownership = crate::ffi::OwnershipRef; - type RustType = $rust_type $(<$lt>)?; - } - }; -} - -pub(crate) use ref_castable; - -/// Defines a new [`Castable`] opaque struct with the specified ownership. -/// -/// In general you should prefer using `box_castable!`, `arc_castable!`, or `ref_castable!` -/// instead of this macro. -macro_rules! castable { - ( - $ownership:ident - $(#[$comment:meta])* - $name:ident - $rust_type:ty - ) => { - $(#[$comment])* - pub struct $name { - _private: [u8; 0], - } - - impl crate::ffi::Castable for $name { - type Ownership = crate::ffi::$ownership; - type RustType = $rust_type; - } - }; -} - -pub(crate) use castable; - /// Convert a const pointer to a [`Castable`] to a const pointer to its underlying /// [`Castable::RustType`]. /// diff --git a/librustls/src/server.rs b/librustls/src/server.rs index e0df7e97..fac04994 100644 --- a/librustls/src/server.rs +++ b/librustls/src/server.rs @@ -18,7 +18,7 @@ use crate::connection::{Connection, rustls_connection}; use crate::crypto_provider::{self, rustls_crypto_provider}; use crate::error::{map_error, rustls_result}; use crate::ffi::{ - Castable, OwnershipRef, arc_castable, box_castable, free_arc, free_box, set_arc_mut_ptr, + Castable, OwnershipArc, OwnershipBox, OwnershipRef, free_arc, free_box, set_arc_mut_ptr, set_boxed_mut_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice, }; @@ -31,20 +31,25 @@ use crate::session::{ use crate::userdata::userdata_get; use crate::verifier::rustls_client_cert_verifier; -box_castable! { - /// A server config being constructed. - /// - /// A builder can be modified by, - /// e.g. rustls_server_config_builder_load_native_roots. Once you're - /// done configuring settings, call rustls_server_config_builder_build - /// to turn it into a *const rustls_server_config. - /// - /// Alternatively, if an error occurs or, you don't wish to build a config, - /// call `rustls_server_config_builder_free` to free the builder directly. - /// - /// This object is not safe for concurrent mutation. - /// - pub struct rustls_server_config_builder(ServerConfigBuilder); +/// A server config being constructed. +/// +/// A builder can be modified by, +/// e.g. rustls_server_config_builder_load_native_roots. Once you're +/// done configuring settings, call rustls_server_config_builder_build +/// to turn it into a *const rustls_server_config. +/// +/// Alternatively, if an error occurs or, you don't wish to build a config, +/// call `rustls_server_config_builder_free` to free the builder directly. +/// +/// This object is not safe for concurrent mutation. +/// +pub struct rustls_server_config_builder { + _private: [u8; 0], +} + +impl Castable for rustls_server_config_builder { + type Ownership = OwnershipBox; + type RustType = ServerConfigBuilder; } pub(crate) struct ServerConfigBuilder { @@ -58,12 +63,17 @@ pub(crate) struct ServerConfigBuilder { key_log: Option>, } -arc_castable! { - /// A server config that is done being constructed and is now read-only. - /// - /// Under the hood, this object corresponds to an `Arc`. - /// - pub struct rustls_server_config(ServerConfig); +/// A server config that is done being constructed and is now read-only. +/// +/// Under the hood, this object corresponds to an `Arc`. +/// +pub struct rustls_server_config { + _private: [u8; 0], +} + +impl Castable for rustls_server_config { + type Ownership = OwnershipArc; + type RustType = ServerConfig; } impl rustls_server_config_builder { diff --git a/librustls/src/verifier.rs b/librustls/src/verifier.rs index 5ddad9c3..52db5509 100644 --- a/librustls/src/verifier.rs +++ b/librustls/src/verifier.rs @@ -16,20 +16,25 @@ use crate::certificate::rustls_root_cert_store; use crate::crypto_provider::{self, rustls_crypto_provider}; use crate::error::{self, rustls_result}; use crate::ffi::{ - box_castable, free_box, set_boxed_mut_ptr, to_boxed_mut_ptr, try_clone_arc, try_mut_from_ptr, - try_mut_from_ptr_ptr, try_slice, try_take, + Castable, OwnershipBox, free_box, set_boxed_mut_ptr, to_boxed_mut_ptr, try_clone_arc, + try_mut_from_ptr, try_mut_from_ptr_ptr, try_slice, try_take, }; use crate::panic::ffi_panic_boundary; -box_castable! { - /// A built client certificate verifier that can be provided to a `rustls_server_config_builder` - /// with `rustls_server_config_builder_set_client_verifier`. - // - // Rustls' ConfigBuilder requires an `Arc` here, meaning we - // must follow the pattern described in CONTRIBUTING.md[^0] for handling dynamically sized - // types (DSTs) across the FFI boundary. - // [^0]: - pub struct rustls_client_cert_verifier(Arc); +/// A built client certificate verifier that can be provided to a `rustls_server_config_builder` +/// with `rustls_server_config_builder_set_client_verifier`. +// +// Rustls' ConfigBuilder requires an `Arc` here, meaning we +// must follow the pattern described in CONTRIBUTING.md[^0] for handling dynamically sized +// types (DSTs) across the FFI boundary. +// [^0]: +pub struct rustls_client_cert_verifier { + _private: [u8; 0], +} + +impl Castable for rustls_client_cert_verifier { + type Ownership = OwnershipBox; + type RustType = Arc; } impl rustls_client_cert_verifier { @@ -54,19 +59,24 @@ pub(crate) struct ClientCertVerifierBuilder { allow_unauthenticated: bool, } -box_castable! { - /// A client certificate verifier being constructed. - /// - /// A builder can be modified by, e.g. `rustls_web_pki_client_cert_verifier_builder_add_crl`. - /// - /// Once you're done configuring settings, call `rustls_web_pki_client_cert_verifier_builder_build` - /// to turn it into a `rustls_client_cert_verifier`. - /// - /// This object is not safe for concurrent mutation. - /// - /// See - /// for more information. - pub struct rustls_web_pki_client_cert_verifier_builder(Option); +/// A client certificate verifier being constructed. +/// +/// A builder can be modified by, e.g. `rustls_web_pki_client_cert_verifier_builder_add_crl`. +/// +/// Once you're done configuring settings, call `rustls_web_pki_client_cert_verifier_builder_build` +/// to turn it into a `rustls_client_cert_verifier`. +/// +/// This object is not safe for concurrent mutation. +/// +/// See +/// for more information. +pub struct rustls_web_pki_client_cert_verifier_builder { + _private: [u8; 0], +} + +impl Castable for rustls_web_pki_client_cert_verifier_builder { + type Ownership = OwnershipBox; + type RustType = Option; } impl rustls_web_pki_client_cert_verifier_builder { @@ -370,17 +380,22 @@ impl rustls_web_pki_client_cert_verifier_builder { } } -box_castable! { - /// A server certificate verifier being constructed. - /// - /// A builder can be modified by, e.g. `rustls_web_pki_server_cert_verifier_builder_add_crl`. - /// - /// Once you're done configuring settings, call `rustls_web_pki_server_cert_verifier_builder_build` - /// to turn it into a `rustls_server_cert_verifier`. This object is not safe for concurrent mutation. - /// - /// See - /// for more information. - pub struct rustls_web_pki_server_cert_verifier_builder(Option); +/// A server certificate verifier being constructed. +/// +/// A builder can be modified by, e.g. `rustls_web_pki_server_cert_verifier_builder_add_crl`. +/// +/// Once you're done configuring settings, call `rustls_web_pki_server_cert_verifier_builder_build` +/// to turn it into a `rustls_server_cert_verifier`. This object is not safe for concurrent mutation. +/// +/// See +/// for more information. +pub struct rustls_web_pki_server_cert_verifier_builder { + _private: [u8; 0], +} + +impl Castable for rustls_web_pki_server_cert_verifier_builder { + type Ownership = OwnershipBox; + type RustType = Option; } pub(crate) struct ServerCertVerifierBuilder { @@ -636,15 +651,20 @@ impl ServerCertVerifierBuilder { } } -box_castable! { - /// A built server certificate verifier that can be provided to a `rustls_client_config_builder` - /// with `rustls_client_config_builder_set_server_verifier`. - // - // Rustls' ConfigBuilder requires an `Arc` here, meaning we - // must follow the pattern described in CONTRIBUTING.md[^0] for handling dynamically sized - // types (DSTs) across the FFI boundary. - // [^0]: - pub struct rustls_server_cert_verifier(Arc); +/// A built server certificate verifier that can be provided to a `rustls_client_config_builder` +/// with `rustls_client_config_builder_set_server_verifier`. +// +// Rustls' ConfigBuilder requires an `Arc` here, meaning we +// must follow the pattern described in CONTRIBUTING.md[^0] for handling dynamically sized +// types (DSTs) across the FFI boundary. +// [^0]: +pub struct rustls_server_cert_verifier { + _private: [u8; 0], +} + +impl Castable for rustls_server_cert_verifier { + type Ownership = OwnershipBox; + type RustType = Arc; } impl rustls_server_cert_verifier { From 16976e2a3d7c725777a5b8963b8755abbe3e8af6 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sun, 28 Sep 2025 13:51:34 -0400 Subject: [PATCH 3/5] librustls: stop using parse.expand Since we have no macros anymore, it's not needed. --- librustls/cbindgen.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/librustls/cbindgen.toml b/librustls/cbindgen.toml index 5f500d06..0b3783eb 100644 --- a/librustls/cbindgen.toml +++ b/librustls/cbindgen.toml @@ -41,7 +41,3 @@ include = ["rustls_tls_version"] "feature = aws-lc-rs" = "DEFINE_AWS_LC_RS" "feature = ring" = "DEFINE_RING" "feature = fips" = "DEFINE_FIPS" - -[parse.expand] -crates = ["rustls-ffi"] -features = ["read_buf", "aws-lc-rs", "ring", "fips"] From b62f8474bd0034966bfa32ba6bd7c83bc733ce72 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sun, 28 Sep 2025 13:46:34 -0400 Subject: [PATCH 4/5] ci: use stable for cbindgen/ensure-header-updated task --- .github/workflows/test.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8a87be89..8c17656d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -271,12 +271,8 @@ jobs: with: persist-credentials: false - - name: Install nightly rust toolchain - uses: dtolnay/rust-toolchain@nightly - with: - # TODO(XXX): remove toolchain pinning once upstream issue is resolved: - # https://github.com/rust-lang/rust/issues/139715 - toolchain: nightly-2025-03-25 + - name: Install stable rust toolchain + uses: dtolnay/rust-toolchain@stable - name: Install cbindgen # Pin the installed version of cbindgen so that local usage can be From 269f7b9a3364520fdbde480f4da841da8d2d7248 Mon Sep 17 00:00:00 2001 From: Joe Birr-Pixton Date: Mon, 27 Oct 2025 08:49:48 +0000 Subject: [PATCH 5/5] error: use decl+proc macro to generate u32 mapping This works because cbindgen does not need to expand derive macros to see the enum items, and cbindgen does not care about the existence of `impl From` for the rust type that the derive outputs. --- Cargo.lock | 23 ++++++ librustls/Cargo.toml | 1 + librustls/src/error.rs | 157 ++++++----------------------------------- librustls/src/lib.rs | 3 + 4 files changed, 48 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc7094ef..86fdd211 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -874,6 +874,22 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "macro_rules_attribute" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" +dependencies = [ + "macro_rules_attribute-proc_macro", + "paste", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" + [[package]] name = "matchers" version = "0.2.0" @@ -1001,6 +1017,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.2" @@ -1230,6 +1252,7 @@ version = "0.15.0" dependencies = [ "libc", "log", + "macro_rules_attribute", "rustls", "rustls-platform-verifier", "rustls-webpki", diff --git a/librustls/Cargo.toml b/librustls/Cargo.toml index fcfc0c0f..ee50fac6 100644 --- a/librustls/Cargo.toml +++ b/librustls/Cargo.toml @@ -35,6 +35,7 @@ webpki = { workspace = true } libc = { workspace = true } log = { workspace = true } rustls-platform-verifier = { workspace = true } +macro_rules_attribute = "0.2.2" [lib] name = "rustls_ffi" diff --git a/librustls/src/error.rs b/librustls/src/error.rs index db730cdd..b520ee0d 100644 --- a/librustls/src/error.rs +++ b/librustls/src/error.rs @@ -20,10 +20,30 @@ use crate::panic::ffi_panic_boundary; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct rustls_io_result(pub libc::c_int); +/// Derive From for our result enum. +macro_rules! ResultFromU32 { + ( + $( #[$attr:meta] )* + $pub:vis enum $NewType:ident { + $($Item:ident = $Value:literal,)* + $(,)? + } + ) => { + impl From for $NewType { + fn from(x: u32) -> Self { + match x { + $($Value => Self::$Item,)* + _ => Self::InvalidParameter, + } + } + } + }; +} + /// Numeric error codes returned from rustls-ffi API functions. #[allow(dead_code)] #[repr(u32)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, ResultFromU32!)] pub enum rustls_result { Ok = 7000, Io = 7001, @@ -189,141 +209,6 @@ pub enum rustls_result { InvalidEncryptedClientHelloSniRequired = 7702, } -impl From for rustls_result { - fn from(x: u32) -> Self { - use rustls_result::*; - - match x { - 7000 => Ok, - 7001 => Io, - 7002 => NullParameter, - 7003 => InvalidDnsNameError, - 7004 => Panic, - 7005 => CertificateParseError, - 7006 => PrivateKeyParseError, - 7007 => InsufficientSize, - 7008 => NotFound, - 7009 => InvalidParameter, - 7010 => UnexpectedEof, - 7011 => PlaintextEmpty, - 7012 => AcceptorNotReady, - 7013 => AlreadyUsed, - 7014 => CertificateRevocationListParseError, - 7015 => NoServerCertVerifier, - 7016 => NoDefaultCryptoProvider, - 7017 => GetRandomFailed, - 7018 => NoCertResolver, - 7019 => HpkeError, - 7020 => BuilderIncompatibleTlsVersions, - 7101 => NoCertificatesPresented, - 7102 => DecryptError, - 7103 => FailedToGetCurrentTime, - 7113 => FailedToGetRandomBytes, - 7104 => HandshakeNotComplete, - 7105 => PeerSentOversizedRecord, - 7106 => NoApplicationProtocol, - 7114 => BadMaxFragmentSize, - 7115 => UnsupportedNameType, - 7116 => EncryptError, - 7121 => CertEncodingBad, - 7122 => CertExpired, - 7123 => CertNotYetValid, - 7124 => CertRevoked, - 7125 => CertUnhandledCriticalExtension, - 7126 => CertUnknownIssuer, - 7127 => CertBadSignature, - 7128 => CertNotValidForName, - 7129 => CertInvalidPurpose, - 7130 => CertApplicationVerificationFailure, - 7131 => CertOtherError, - 7154 => CertUnknownRevocationStatus, - 7156 => CertExpiredRevocationList, - 7157 => CertUnsupportedSignatureAlgorithm, - 7133 => MessageHandshakePayloadTooLarge, - 7134 => MessageInvalidCcs, - 7135 => MessageInvalidContentType, - 7136 => MessageInvalidCertStatusType, - 7137 => MessageInvalidCertRequest, - 7138 => MessageInvalidDhParams, - 7139 => MessageInvalidEmptyPayload, - 7140 => MessageInvalidKeyUpdate, - 7141 => MessageInvalidServerName, - 7142 => MessageTooLarge, - 7143 => MessageTooShort, - 7144 => MessageMissingData, - 7145 => MessageMissingKeyExchange, - 7146 => MessageNoSignatureSchemes, - 7147 => MessageTrailingData, - 7148 => MessageUnexpectedMessage, - 7149 => MessageUnknownProtocolVersion, - 7150 => MessageUnsupportedCompression, - 7151 => MessageUnsupportedCurveType, - 7152 => MessageUnsupportedKeyExchangeAlgorithm, - 7153 => MessageInvalidOther, - 7155 => MessageCertificatePayloadTooLarge, - 7107 => PeerIncompatibleError, - 7108 => PeerMisbehavedError, - 7109 => InappropriateMessage, - 7110 => InappropriateHandshakeMessage, - 7112 => General, - 7200 => AlertCloseNotify, - 7201 => AlertUnexpectedMessage, - 7202 => AlertBadRecordMac, - 7203 => AlertDecryptionFailed, - 7204 => AlertRecordOverflow, - 7205 => AlertDecompressionFailure, - 7206 => AlertHandshakeFailure, - 7207 => AlertNoCertificate, - 7208 => AlertBadCertificate, - 7209 => AlertUnsupportedCertificate, - 7210 => AlertCertificateRevoked, - 7211 => AlertCertificateExpired, - 7212 => AlertCertificateUnknown, - 7213 => AlertIllegalParameter, - 7214 => AlertUnknownCA, - 7215 => AlertAccessDenied, - 7216 => AlertDecodeError, - 7217 => AlertDecryptError, - 7218 => AlertExportRestriction, - 7219 => AlertProtocolVersion, - 7220 => AlertInsufficientSecurity, - 7221 => AlertInternalError, - 7222 => AlertInappropriateFallback, - 7223 => AlertUserCanceled, - 7224 => AlertNoRenegotiation, - 7225 => AlertMissingExtension, - 7226 => AlertUnsupportedExtension, - 7227 => AlertCertificateUnobtainable, - 7228 => AlertUnrecognisedName, - 7229 => AlertBadCertificateStatusResponse, - 7230 => AlertBadCertificateHashValue, - 7231 => AlertUnknownPSKIdentity, - 7232 => AlertCertificateRequired, - 7233 => AlertNoApplicationProtocol, - 7234 => AlertUnknown, - 7400 => CertRevocationListBadSignature, - 7401 => CertRevocationListInvalidCrlNumber, - 7402 => CertRevocationListInvalidRevokedCertSerialNumber, - 7403 => CertRevocationListIssuerInvalidForCrl, - 7404 => CertRevocationListOtherError, - 7405 => CertRevocationListParseError, - 7406 => CertRevocationListUnsupportedCrlVersion, - 7407 => CertRevocationListUnsupportedCriticalExtension, - 7408 => CertRevocationListUnsupportedDeltaCrl, - 7409 => CertRevocationListUnsupportedIndirectCrl, - 7410 => CertRevocationListUnsupportedRevocationReason, - 7411 => CertRevocationListUnsupportedSignatureAlgorithm, - 7500 => ClientCertVerifierBuilderNoRootAnchors, - 7600 => InconsistentKeysKeysMismatch, - 7601 => InconsistentKeysUnknown, - 7700 => InvalidEncryptedClientHelloInvalidConfigList, - 7701 => InvalidEncryptedClientHelloNoCompatibleConfig, - 7702 => InvalidEncryptedClientHelloSniRequired, - _ => InvalidParameter, - } - } -} - impl rustls_result { /// After a rustls function returns an error, you may call /// this to get a pointer to a buffer containing a detailed error diff --git a/librustls/src/lib.rs b/librustls/src/lib.rs index 24be64af..5960ef77 100644 --- a/librustls/src/lib.rs +++ b/librustls/src/lib.rs @@ -40,3 +40,6 @@ pub mod version; pub use error::rustls_result; pub use error::*; pub use version::rustls_version; + +#[macro_use] +extern crate macro_rules_attribute;