blob: 8ab11e0bd4057c5fe4d7e32a6b1e6a2ac2166c5d [file]
// Copyright 2026 The BoringSSL Authors
//
// Licensed under the Apache License, Version 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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use core::ptr::null;
use bssl_crypto::FromFfiSlice;
use crate::{
alpn::AlpnProtocols,
config::ConfigurationError,
connection::lifecycle::{
EstablishedTlsConnection,
TlsConnectionInHandshake, //
},
errors::Error,
ffi::slice_into_ffi_raw_parts, //
};
impl<R, M> TlsConnectionInHandshake<'_, R, M> {
/// Set ALPN protocols.
///
/// Per [RFC 7301], empty protocol names, names longer than 255 bytes are invalid.
/// Also, the total size of the ALPN protocol list must not exceed [`u16::MAX`] bytes.
///
/// **This method has no effect after handshake completion.**
///
/// [RFC 7301]: <https://datatracker.ietf.org/doc/html/rfc7301#section-3.1>
pub fn set_alpn_protocols<'a>(
&mut self,
protocols: impl IntoIterator<Item = &'a [u8]>,
) -> Result<&mut Self, Error> {
let mut protos = AlpnProtocols::default();
for proto in protocols {
protos
.append_protocol(proto)
.map_err(|_| Error::Configuration(ConfigurationError::InvalidAlpnProtocols))?;
}
let (protos, len) = slice_into_ffi_raw_parts(protos.as_slice());
let rc = unsafe {
// Safety:
// - the validity of the handle `self.ptr()` is witnessed by `self`.
// - the validity of ALPN string is guaranteed by `AlpnProtocols` type.
// Note: `SSL_set_alpn_protos` flips the return value around.
bssl_sys::SSL_set_alpn_protos(self.ptr(), protos, len)
};
if rc == 1 {
Err(Error::extract_lib_err())
} else {
Ok(self)
}
}
}
/// Application-layer Protocol Negotiation.
impl<R, M> EstablishedTlsConnection<'_, R, M> {
/// Get the selected Application-layer Protocol.
///
/// This function returns [`None`] when no ALPN protocol was negotiated.
pub fn get_selected_alpn(&self) -> Option<&[u8]> {
let mut name = null();
let mut len = 0;
unsafe {
// Safety: the validity of the handle `self.ptr()` is witnessed by `self`.
bssl_sys::SSL_get0_alpn_selected(self.ptr(), &raw mut name, &raw mut len);
}
let Ok(len) = usize::try_from(len) else {
panic!("invalid slice length")
};
let proto = unsafe {
// Safety:
// - `self` outlives the output slice.
// - `name` is generated by BoringSSL.
u8::from_ffi_ptr(name, len)
};
(!proto.is_empty()).then_some(proto)
}
}