Skip to content

Commit 3bb19d8

Browse files
Merge #57
57: Add accessors for X.509 certificate fields r=Goirad a=jack-fortanix This changes the behavior of `issuer_raw` and `subject_raw`. Currently those return the same value as issuer/subject, except as `Vec<u8>` instead of `String`s, which is just duplicating `String::into_bytes`. IMO they should instead return the raw binary DER which allows accessing fields in the DN which mbedtls doesn't know about or can't handle: `mbedtls_x509_dn_gets` prints OIDs it doesn't know as "??", and characters in ranges 0...32 and 128..160 as '?', meaning it mangles UTF-8 and UCS-2 names. Co-authored-by: Jack Lloyd <[email protected]>
2 parents f447f7d + 0c5e04b commit 3bb19d8

File tree

4 files changed

+99
-13
lines changed

4 files changed

+99
-13
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mbedtls/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ path = "../mbedtls-sys"
4242
libc = "0.2.0"
4343
rand = "0.4.0"
4444
serde_cbor = "0.6"
45+
hex = "0.3"
4546

4647
[build-dependencies]
4748
cc = "1.0"

mbedtls/src/x509/certificate.rs

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ use crate::private::UnsafeFrom;
2323
use crate::rng::Random;
2424
use crate::hash::Type as MdType;
2525

26+
#[derive(Debug,Copy,Clone,Eq,PartialEq)]
27+
pub enum CertificateVersion {
28+
V1,
29+
V2,
30+
V3
31+
}
32+
2633
define!(
2734
#[c_ty(x509_crt)]
2835
struct Certificate;
@@ -114,6 +121,24 @@ pub struct LinkedCertificate {
114121
inner: x509_crt,
115122
}
116123

124+
fn x509_buf_to_vec(buf: &x509_buf) -> Vec<u8> {
125+
if buf.p == core::ptr::null_mut() || buf.len == 0 {
126+
return vec![];
127+
}
128+
129+
let slice = unsafe { core::slice::from_raw_parts(buf.p, buf.len) };
130+
slice.to_owned()
131+
}
132+
133+
fn x509_time_to_time(tm: &x509_time) -> Result<super::Time> {
134+
// ensure casts don't underflow
135+
if tm.year < 0 || tm.mon < 0 || tm.day < 0 || tm.hour < 0 || tm.min < 0 || tm.sec < 0 {
136+
return Err(Error::X509InvalidDate);
137+
}
138+
139+
super::Time::new(tm.year as u16, tm.mon as u8, tm.day as u8, tm.hour as u8, tm.min as u8, tm.sec as u8).ok_or(Error::X509InvalidDate)
140+
}
141+
117142
impl LinkedCertificate {
118143
pub fn check_key_usage(&self, usage: super::KeyUsage) -> bool {
119144
unsafe { x509_crt_check_key_usage(&self.inner, usage.bits()) }
@@ -136,10 +161,7 @@ impl LinkedCertificate {
136161
}
137162

138163
pub fn issuer_raw(&self) -> Result<Vec<u8>> {
139-
crate::private::alloc_vec_repeat(
140-
|buf, size| unsafe { x509_dn_gets(buf as _, size, &self.inner.issuer) },
141-
false,
142-
)
164+
Ok(x509_buf_to_vec(&self.inner.issuer_raw))
143165
}
144166

145167
pub fn subject(&self) -> Result<String> {
@@ -149,10 +171,7 @@ impl LinkedCertificate {
149171
}
150172

151173
pub fn subject_raw(&self) -> Result<Vec<u8>> {
152-
crate::private::alloc_vec_repeat(
153-
|buf, size| unsafe { x509_dn_gets(buf as _, size, &self.inner.subject) },
154-
false,
155-
)
174+
Ok(x509_buf_to_vec(&self.inner.subject_raw))
156175
}
157176

158177
pub fn serial(&self) -> Result<String> {
@@ -162,10 +181,7 @@ impl LinkedCertificate {
162181
}
163182

164183
pub fn serial_raw(&self) -> Result<Vec<u8>> {
165-
crate::private::alloc_vec_repeat(
166-
|buf, size| unsafe { x509_serial_gets(buf as _, size, &self.inner.serial) },
167-
false,
168-
)
184+
Ok(x509_buf_to_vec(&self.inner.serial))
169185
}
170186

171187
pub fn public_key(&self) -> &Pk {
@@ -180,6 +196,31 @@ impl LinkedCertificate {
180196
unsafe { ::core::slice::from_raw_parts(self.inner.raw.p, self.inner.raw.len) }
181197
}
182198

199+
pub fn version(&self) -> Result<CertificateVersion> {
200+
match self.inner.version {
201+
1 => Ok(CertificateVersion::V1),
202+
2 => Ok(CertificateVersion::V2),
203+
3 => Ok(CertificateVersion::V3),
204+
_ => Err(Error::X509InvalidVersion)
205+
}
206+
}
207+
208+
pub fn not_before(&self) -> Result<super::Time> {
209+
x509_time_to_time(&self.inner.valid_from)
210+
}
211+
212+
pub fn not_after(&self) -> Result<super::Time> {
213+
x509_time_to_time(&self.inner.valid_to)
214+
}
215+
216+
pub fn extensions_raw(&self) -> Result<Vec<u8>> {
217+
Ok(x509_buf_to_vec(&self.inner.v3_ext))
218+
}
219+
220+
pub fn signature(&self) -> Result<Vec<u8>> {
221+
Ok(x509_buf_to_vec(&self.inner.sig))
222+
}
223+
183224
pub fn digest_type(&self) -> MdType {
184225
MdType::from(self.inner.sig_md)
185226
}
@@ -722,7 +763,7 @@ JS7pkcufTIoN0Yj0SxAWLW711FgB
722763
}
723764

724765
#[test]
725-
fn channel_binding_hash() {
766+
fn cert_field_access() {
726767
const TEST_CERT_PEM: &'static str = "-----BEGIN CERTIFICATE-----
727768
MIIDLDCCAhSgAwIBAgIRALY0SS5pY9Yb/aIHvSAvmOswDQYJKoZIhvcNAQELBQAw
728769
HzEQMA4GA1UEAxMHVGVzdCBDQTELMAkGA1UEBhMCVVMwHhcNMTkwMTA4MDAxODM1
@@ -745,6 +786,7 @@ cYp0bH/RcPTC0Z+ZaqSWMtfxRrk63MJQF9EXpDCdvQRcTMD9D85DJrMKn8aumq0M
745786

746787
let cert = Certificate::from_pem(&TEST_CERT_PEM.as_bytes()).unwrap();
747788

789+
assert_eq!(cert.version().unwrap(), CertificateVersion::V3);
748790
assert_eq!(cert.issuer().unwrap(), "CN=Test CA, C=US");
749791
assert_eq!(cert.subject().unwrap(), "CN=Test Cert, O=Test");
750792
assert_eq!(
@@ -753,6 +795,41 @@ cYp0bH/RcPTC0Z+ZaqSWMtfxRrk63MJQF9EXpDCdvQRcTMD9D85DJrMKn8aumq0M
753795
);
754796
assert_eq!(cert.digest_type(), MdType::Sha256);
755797

798+
assert_eq!(hex::encode(cert.serial_raw().unwrap()), "00b634492e6963d61bfda207bd202f98eb");
799+
assert_eq!(hex::encode(cert.issuer_raw().unwrap()), "301f3110300e0603550403130754657374204341310b3009060355040613025553");
800+
assert_eq!(hex::encode(cert.subject_raw().unwrap()), "30233112301006035504031309546573742043657274310d300b060355040a130454657374");
801+
assert_eq!(hex::encode(cert.signature().unwrap()), "4a4b2638e636a0c0121b0334e04b342ac17b178b1a3000d5dc84c0612941519e3ac99da72823809e643f9d1c0ff7ca2734c63974215879f6286532d43b0da6086fb212a96c8f573de4230c9ab3ae09d621719d2e35b3e91963d5e763a273f0e25d6bbc5fcd0cd7ace688821df1724fb3956c96046cd58126f3ae2a66680cccc8aaecbe680fa5fc79684ef33f64153b319713f42ea17aa3fdb99b94d95466ed75e572789d2c7388a49d35a6590429fe9b6959896e8658aee276f3474ff315051e6633be236d2acf552164ea6936122f9d718a746c7fd170f4c2d19f996aa49632d7f146b93adcc25017d117a4309dbd045c4cc0fd0fce4326b30a9fc6ae9aad0c");
802+
assert_eq!(hex::encode(cert.extensions_raw().unwrap()), "30819f30210603551d0e041a04186839fad57e6544121cc6bc421953cc9620655c57cfac060230320603551d11042b302981117465737440666f7274616e69782e636f6d82146578616d706c652e666f7274616e69782e636f6d300c0603551d130101ff0402300030230603551d23041c301a801879076bcc8da0077e4116f84b8e4c9c5c6af7ec4fa000d98730130603551d25040c300a06082b06010505070302");
803+
804+
use crate::x509::Time;
805+
assert_eq!(cert.not_before().unwrap(), Time::new(2019,1,8,0,18,35).unwrap());
806+
assert_eq!(cert.not_after().unwrap(), Time::new(2029,1,5,0,18,35).unwrap());
807+
}
808+
809+
#[test]
810+
fn channel_binding_hash() {
811+
const TEST_CERT_PEM: &'static str = "-----BEGIN CERTIFICATE-----
812+
MIIDLDCCAhSgAwIBAgIRALY0SS5pY9Yb/aIHvSAvmOswDQYJKoZIhvcNAQELBQAw
813+
HzEQMA4GA1UEAxMHVGVzdCBDQTELMAkGA1UEBhMCVVMwHhcNMTkwMTA4MDAxODM1
814+
WhcNMjkwMTA1MDAxODM1WjAjMRIwEAYDVQQDEwlUZXN0IENlcnQxDTALBgNVBAoT
815+
BFRlc3Qwgd8wDQYJKoZIhvcNAQEBBQADgc0AMIHJAoHBAKYINzSAKG1/Kn/5dWXq
816+
cfJgfQkzVn1HPzdb4NNZL+H7woGuzDGrcQ7EPi7r4EuAEE2fCjhSfiYlacoBOxd/
817+
k9Fp4Iv2ygCY1nj8RY0tFCZcZDVYj5F7uqyJMf7+QSOpnZ4cb3zdj1HkBmq7ac0C
818+
7tXkubvM6gBS3H3XlhfszcEjvhavaxVVoitdqW8RJ2DHvqGwFUxPgFCuuQudeCI/
819+
UzBiPMRqu3Pr9Xhcc0ruG5SkCg5isbWWnKNj7X1gTre6WwIDAQABo4GiMIGfMCEG
820+
A1UdDgQaBBhoOfrVfmVEEhzGvEIZU8yWIGVcV8+sBgIwMgYDVR0RBCswKYERdGVz
821+
dEBmb3J0YW5peC5jb22CFGV4YW1wbGUuZm9ydGFuaXguY29tMAwGA1UdEwEB/wQC
822+
MAAwIwYDVR0jBBwwGoAYeQdrzI2gB35BFvhLjkycXGr37E+gANmHMBMGA1UdJQQM
823+
MAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBKSyY45jagwBIbAzTgSzQq
824+
wXsXixowANXchMBhKUFRnjrJnacoI4CeZD+dHA/3yic0xjl0IVh59ihlMtQ7DaYI
825+
b7ISqWyPVz3kIwyas64J1iFxnS41s+kZY9XnY6Jz8OJda7xfzQzXrOaIgh3xck+z
826+
lWyWBGzVgSbzripmaAzMyKrsvmgPpfx5aE7zP2QVOzGXE/QuoXqj/bmblNlUZu11
827+
5XJ4nSxziKSdNaZZBCn+m2lZiW6GWK7idvNHT/MVBR5mM74jbSrPVSFk6mk2Ei+d
828+
cYp0bH/RcPTC0Z+ZaqSWMtfxRrk63MJQF9EXpDCdvQRcTMD9D85DJrMKn8aumq0M
829+
-----END CERTIFICATE-----\0";
830+
831+
let cert = Certificate::from_pem(&TEST_CERT_PEM.as_bytes()).unwrap();
832+
756833
let pk = cert.public_key();
757834

758835
assert_eq!(pk.pk_type(), crate::pk::Type::Rsa);

mbedtls/src/x509/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ bitflags! {
7878
}
7979

8080
/// A specific moment in time in UTC
81+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8182
pub struct Time {
8283
year: u16,
8384
month: u8,

0 commit comments

Comments
 (0)