Skip to content

Commit 79338a9

Browse files
committed
CStr UTF-8 improvements
1 parent 330bf82 commit 79338a9

File tree

8 files changed

+77
-50
lines changed

8 files changed

+77
-50
lines changed

boring/src/asn1.rs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,19 @@ foreign_type_and_impl_send_sync! {
6363

6464
impl fmt::Display for Asn1GeneralizedTimeRef {
6565
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66-
unsafe {
67-
let mem_bio = match MemBio::new() {
68-
Err(_) => return f.write_str("error"),
69-
Ok(m) => m,
70-
};
71-
let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print(
72-
mem_bio.as_ptr(),
73-
self.as_ptr(),
74-
));
75-
match print_result {
76-
Err(_) => f.write_str("error"),
77-
Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
78-
}
79-
}
66+
let bio = MemBio::new().ok();
67+
let msg = bio
68+
.as_ref()
69+
.and_then(|mem_bio| unsafe {
70+
cvt(ffi::ASN1_GENERALIZEDTIME_print(
71+
mem_bio.as_ptr(),
72+
self.as_ptr(),
73+
))
74+
.ok()?;
75+
str::from_utf8(mem_bio.get_buf()).ok()
76+
})
77+
.unwrap_or("error");
78+
f.write_str(msg)
8079
}
8180
}
8281

@@ -528,7 +527,20 @@ impl Asn1BitStringRef {
528527
#[corresponds(ASN1_STRING_get0_data)]
529528
#[must_use]
530529
pub fn as_slice(&self) -> &[u8] {
531-
unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
530+
unsafe {
531+
let ptr = ASN1_STRING_get0_data(self.as_ptr().cast());
532+
if ptr.is_null() {
533+
return &[];
534+
}
535+
slice::from_raw_parts(ptr, self.len())
536+
}
537+
}
538+
539+
/// Returns the Asn1BitString as a str, if possible.
540+
#[corresponds(ASN1_STRING_get0_data)]
541+
#[must_use]
542+
pub fn to_str(&self) -> Option<&str> {
543+
str::from_utf8(self.as_slice()).ok()
532544
}
533545

534546
/// Returns the number of bytes in the string.
@@ -601,10 +613,11 @@ impl fmt::Display for Asn1ObjectRef {
601613
self.as_ptr(),
602614
0,
603615
);
604-
match str::from_utf8(&buf[..len as usize]) {
605-
Err(_) => fmt.write_str("error"),
606-
Ok(s) => fmt.write_str(s),
607-
}
616+
fmt.write_str(
617+
buf.get(..len as usize)
618+
.and_then(|s| str::from_utf8(s).ok())
619+
.unwrap_or("error"),
620+
)
608621
}
609622
}
610623
}

boring/src/bio.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ impl MemBio {
6868
unsafe {
6969
let mut ptr = ptr::null_mut();
7070
let len = ffi::BIO_get_mem_data(self.0, &mut ptr);
71-
slice::from_raw_parts(ptr as *const _ as *const _, len as usize)
71+
if ptr.is_null() {
72+
return &[];
73+
}
74+
slice::from_raw_parts(ptr.cast_const().cast(), len as usize)
7275
}
7376
}
7477
}

boring/src/error.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ impl Error {
146146
// The memory referenced by data is only valid until that slot is overwritten
147147
// in the error stack, so we'll need to copy it off if it's dynamic
148148
let data = if flags & ffi::ERR_FLAG_STRING != 0 {
149-
let bytes = CStr::from_ptr(data as *const _).to_bytes();
150-
let data = String::from_utf8_lossy(bytes).into_owned();
151-
Some(data.into())
149+
Some(Cow::Owned(
150+
CStr::from_ptr(data.cast()).to_string_lossy().into_owned(),
151+
))
152152
} else {
153153
None
154154
};
@@ -214,8 +214,10 @@ impl Error {
214214
if cstr.is_null() {
215215
return None;
216216
}
217-
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
218-
str::from_utf8(bytes).ok()
217+
CStr::from_ptr(cstr.cast())
218+
.to_str()
219+
.ok()
220+
.filter(|&msg| msg != "unknown library")
219221
}
220222
}
221223

@@ -240,8 +242,7 @@ impl Error {
240242
if cstr.is_null() {
241243
return None;
242244
}
243-
let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
244-
str::from_utf8(bytes).ok()
245+
CStr::from_ptr(cstr.cast()).to_str().ok()
245246
}
246247
}
247248

@@ -263,8 +264,9 @@ impl Error {
263264
if self.file.is_null() {
264265
return "";
265266
}
266-
let bytes = CStr::from_ptr(self.file as *const _).to_bytes();
267-
str::from_utf8(bytes).unwrap_or_default()
267+
CStr::from_ptr(self.file.cast())
268+
.to_str()
269+
.unwrap_or_default()
268270
}
269271
}
270272

boring/src/nid.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ impl Nid {
8888
pub fn long_name(&self) -> Result<&'static str, ErrorStack> {
8989
unsafe {
9090
let nameptr = cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char)?;
91-
str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).map_err(ErrorStack::internal_error)
91+
CStr::from_ptr(nameptr)
92+
.to_str()
93+
.map_err(ErrorStack::internal_error)
9294
}
9395
}
9496

@@ -98,7 +100,9 @@ impl Nid {
98100
pub fn short_name(&self) -> Result<&'static str, ErrorStack> {
99101
unsafe {
100102
let nameptr = cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char)?;
101-
str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).map_err(ErrorStack::internal_error)
103+
CStr::from_ptr(nameptr)
104+
.to_str()
105+
.map_err(ErrorStack::internal_error)
102106
}
103107
}
104108

boring/src/ssl/callbacks.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,14 +451,14 @@ where
451451
{
452452
// SAFETY: boring provides valid inputs.
453453
let ssl = unsafe { SslRef::from_ptr(ssl as *mut _) };
454-
let line = unsafe { str::from_utf8_unchecked(CStr::from_ptr(line).to_bytes()) };
454+
let line = unsafe { CStr::from_ptr(line).to_string_lossy() };
455455

456456
let callback = ssl
457457
.ssl_context()
458458
.ex_data(SslContext::cached_ex_index::<F>())
459459
.expect("BUG: get session callback missing");
460460

461-
callback(ssl, line);
461+
callback(ssl, &line);
462462
}
463463

464464
pub(super) unsafe extern "C" fn raw_sign<M>(

boring/src/ssl/mod.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,7 +2564,7 @@ impl SslCipherRef {
25642564
CStr::from_ptr(ptr as *const _)
25652565
};
25662566

2567-
str::from_utf8(version.to_bytes()).unwrap()
2567+
version.to_str().unwrap()
25682568
}
25692569

25702570
/// Returns the number of bits used for the cipher.
@@ -2590,7 +2590,7 @@ impl SslCipherRef {
25902590
// SSL_CIPHER_description requires a buffer of at least 128 bytes.
25912591
let mut buf = [0; 128];
25922592
let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
2593-
String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap()
2593+
CStr::from_ptr(ptr.cast()).to_string_lossy().into_owned()
25942594
}
25952595
}
25962596

@@ -3216,6 +3216,8 @@ impl SslRef {
32163216
}
32173217

32183218
/// Returns a short string describing the state of the session.
3219+
///
3220+
/// Returns empty string if the state wasn't valid UTF-8
32193221
#[corresponds(SSL_state_string)]
32203222
#[must_use]
32213223
pub fn state_string(&self) -> &'static str {
@@ -3224,10 +3226,12 @@ impl SslRef {
32243226
CStr::from_ptr(ptr as *const _)
32253227
};
32263228

3227-
str::from_utf8(state.to_bytes()).unwrap()
3229+
state.to_str().unwrap_or_default()
32283230
}
32293231

32303232
/// Returns a longer string describing the state of the session.
3233+
///
3234+
/// Returns empty string if the state wasn't valid UTF-8
32313235
#[corresponds(SSL_state_string_long)]
32323236
#[must_use]
32333237
pub fn state_string_long(&self) -> &'static str {
@@ -3236,7 +3240,7 @@ impl SslRef {
32363240
CStr::from_ptr(ptr as *const _)
32373241
};
32383242

3239-
str::from_utf8(state.to_bytes()).unwrap()
3243+
state.to_str().unwrap_or_default()
32403244
}
32413245

32423246
/// Sets the host name to be sent to the server for Server Name Indication (SNI).
@@ -3348,6 +3352,8 @@ impl SslRef {
33483352
}
33493353

33503354
/// Returns a string describing the protocol version of the session.
3355+
///
3356+
/// This may panic if the string isn't valid UTF-8 for some reason. Use [`Self::version2`] instead.
33513357
#[corresponds(SSL_get_version)]
33523358
#[must_use]
33533359
pub fn version_str(&self) -> &'static str {
@@ -3356,7 +3362,7 @@ impl SslRef {
33563362
CStr::from_ptr(ptr as *const _)
33573363
};
33583364

3359-
str::from_utf8(version.to_bytes()).unwrap()
3365+
version.to_str().unwrap()
33603366
}
33613367

33623368
/// Sets the minimum supported protocol version.

boring/src/string.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ foreign_type_and_impl_send_sync! {
1313
type CType = c_char;
1414
fn drop = free;
1515

16+
/// # Safety
17+
///
18+
/// MUST be UTF-8
1619
pub struct OpensslString;
1720
}
1821

boring/src/x509/mod.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use std::mem;
1919
use std::net::IpAddr;
2020
use std::path::Path;
2121
use std::ptr;
22-
use std::slice;
2322
use std::str;
2423
use std::sync::{LazyLock, Once};
2524

@@ -1535,6 +1534,8 @@ impl X509VerifyError {
15351534
}
15361535

15371536
/// Return a human readable error string from the verification error.
1537+
///
1538+
/// Returns empty string if the message was not UTF-8
15381539
#[corresponds(X509_verify_cert_error_string)]
15391540
#[allow(clippy::trivially_copy_pass_by_ref)]
15401541
#[must_use]
@@ -1543,7 +1544,7 @@ impl X509VerifyError {
15431544

15441545
unsafe {
15451546
let s = ffi::X509_verify_cert_error_string(c_long::from(self.0));
1546-
str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
1547+
CStr::from_ptr(s).to_str().unwrap_or_default()
15471548
}
15481549
}
15491550
}
@@ -1695,14 +1696,12 @@ impl GeneralNameRef {
16951696
return None;
16961697
}
16971698

1698-
let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ia5 as *mut _);
1699-
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ia5 as *mut _);
1699+
let asn = Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ia5);
17001700

1701-
let slice = slice::from_raw_parts(ptr, len as usize);
17021701
// IA5Strings are stated to be ASCII (specifically IA5). Hopefully
17031702
// OpenSSL checks that when loading a certificate but if not we'll
17041703
// use this instead of from_utf8_unchecked just in case.
1705-
str::from_utf8(slice).ok()
1704+
asn.to_str()
17061705
}
17071706
}
17081707

@@ -1732,10 +1731,7 @@ impl GeneralNameRef {
17321731
return None;
17331732
}
17341733

1735-
let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d.ip as *mut _);
1736-
let len = ffi::ASN1_STRING_length((*self.as_ptr()).d.ip as *mut _);
1737-
1738-
Some(slice::from_raw_parts(ptr, len as usize))
1734+
Some(Asn1BitStringRef::from_ptr((*self.as_ptr()).d.ip).as_slice())
17391735
}
17401736
}
17411737
}
@@ -1811,8 +1807,8 @@ impl Stackable for X509Object {
18111807
use crate::ffi::{X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref};
18121808

18131809
use crate::ffi::{
1814-
ASN1_STRING_get0_data, X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version,
1815-
X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore,
1810+
X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version, X509_STORE_CTX_get0_chain,
1811+
X509_set1_notAfter, X509_set1_notBefore,
18161812
};
18171813

18181814
use crate::ffi::X509_OBJECT_get0_X509;

0 commit comments

Comments
 (0)