@@ -7,8 +7,31 @@ use core_foundation_sys::base::kCFAllocatorDefault;
7
7
use security_framework_sys:: base:: { errSecParam, SecCertificateRef } ;
8
8
use security_framework_sys:: certificate:: * ;
9
9
use std:: fmt;
10
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
11
+ use std:: ptr;
10
12
11
13
use base:: { Error , Result } ;
14
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
15
+ use core_foundation:: base:: FromVoid ;
16
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
17
+ use core_foundation:: number:: CFNumber ;
18
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
19
+ use core_foundation_sys:: base:: CFRelease ;
20
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
21
+ use security_framework_sys:: base:: SecPolicyRef ;
22
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
23
+ use security_framework_sys:: item:: * ;
24
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
25
+ use security_framework_sys:: policy:: SecPolicyCreateBasicX509 ;
26
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
27
+ use security_framework_sys:: trust:: {
28
+ SecTrustCopyPublicKey , SecTrustCreateWithCertificates , SecTrustEvaluate , SecTrustRef ,
29
+ SecTrustResultType ,
30
+ } ;
31
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
32
+ use std:: ops:: Deref ;
33
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
34
+ use { cvt, key} ;
12
35
13
36
declare_TCFType ! {
14
37
/// A type representing a certificate.
@@ -57,8 +80,107 @@ impl SecCertificate {
57
80
CFString :: wrap_under_create_rule ( summary) . to_string ( )
58
81
}
59
82
}
83
+
84
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
85
+ /// Returns DER encoded subjectPublicKeyInfo of certificate if available. This can be used
86
+ /// for certificate pinning.
87
+ pub fn public_key_info_der ( & self ) -> Result < Option < Vec < u8 > > > {
88
+ // Imported from TrustKit
89
+ // https://github.com/datatheorem/TrustKit/blob/master/TrustKit/Pinning/TSKSPKIHashCache.m
90
+ let public_key = self . public_key ( ) ?;
91
+ Ok ( self . pk_to_der ( public_key) )
92
+ }
93
+
94
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
95
+ fn pk_to_der ( & self , public_key : key:: SecKey ) -> Option < Vec < u8 > > {
96
+ let public_key_attributes = public_key. attributes ( ) ;
97
+ let public_key_type =
98
+ public_key_attributes. find ( unsafe { kSecAttrKeyType } as * const std:: os:: raw:: c_void ) ?;
99
+ let public_keysize = public_key_attributes
100
+ . find ( unsafe { kSecAttrKeySizeInBits } as * const std:: os:: raw:: c_void ) ?;
101
+ let public_keysize = unsafe { CFNumber :: from_void ( * public_keysize. deref ( ) ) } ;
102
+ let public_keysize_val = public_keysize. to_i64 ( ) ? as u32 ;
103
+ let hdr_bytes = get_asn1_header_bytes (
104
+ unsafe { CFString :: wrap_under_get_rule ( * public_key_type. deref ( ) as _ ) } ,
105
+ public_keysize_val,
106
+ ) ?;
107
+ let public_key_data = public_key. external_representation ( ) ?;
108
+ let mut out = Vec :: with_capacity ( hdr_bytes. len ( ) + public_key_data. len ( ) as usize ) ;
109
+ out. extend_from_slice ( hdr_bytes) ;
110
+ out. extend_from_slice ( public_key_data. bytes ( ) ) ;
111
+ Some ( out)
112
+ }
113
+
114
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
115
+ /// Get public key from certificate
116
+ pub fn public_key ( & self ) -> Result < key:: SecKey > {
117
+ unsafe {
118
+ // Create an X509 trust using the using the certificate
119
+ let mut trust: SecTrustRef = ptr:: null_mut ( ) ;
120
+ let policy: SecPolicyRef = SecPolicyCreateBasicX509 ( ) ;
121
+ cvt ( SecTrustCreateWithCertificates (
122
+ self . as_concrete_TypeRef ( ) as _ ,
123
+ policy as _ ,
124
+ & mut trust,
125
+ ) ) ?;
126
+
127
+ // Get a public key reference for the certificate from the trust
128
+ let mut result: SecTrustResultType = 0 ;
129
+ cvt ( SecTrustEvaluate ( trust, & mut result) ) ?;
130
+ let public_key = SecTrustCopyPublicKey ( trust) ;
131
+ CFRelease ( policy as _ ) ;
132
+ CFRelease ( trust as _ ) ;
133
+
134
+ Ok ( key:: SecKey :: wrap_under_create_rule ( public_key) )
135
+ }
136
+ }
60
137
}
61
138
139
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
140
+ fn get_asn1_header_bytes ( pkt : CFString , ksz : u32 ) -> Option < & ' static [ u8 ] > {
141
+ if pkt == unsafe { CFString :: wrap_under_get_rule ( kSecAttrKeyTypeRSA) } && ksz == 2048 {
142
+ return Some ( & RSA_2048_ASN1_HEADER ) ;
143
+ }
144
+ if pkt == unsafe { CFString :: wrap_under_get_rule ( kSecAttrKeyTypeRSA) } && ksz == 4096 {
145
+ return Some ( & RSA_4096_ASN1_HEADER ) ;
146
+ }
147
+ if pkt == unsafe { CFString :: wrap_under_get_rule ( kSecAttrKeyTypeECSECPrimeRandom) }
148
+ && ksz == 256
149
+ {
150
+ return Some ( & EC_DSA_SECP_256_R1_ASN1_HEADER ) ;
151
+ }
152
+ if pkt == unsafe { CFString :: wrap_under_get_rule ( kSecAttrKeyTypeECSECPrimeRandom) }
153
+ && ksz == 384
154
+ {
155
+ return Some ( & EC_DSA_SECP_384_R1_ASN1_HEADER ) ;
156
+ }
157
+ None
158
+ }
159
+
160
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
161
+ const RSA_2048_ASN1_HEADER : [ u8 ; 24 ] = [
162
+ 0x30 , 0x82 , 0x01 , 0x22 , 0x30 , 0x0d , 0x06 , 0x09 , 0x2a , 0x86 , 0x48 , 0x86 , 0xf7 , 0x0d , 0x01 , 0x01 ,
163
+ 0x01 , 0x05 , 0x00 , 0x03 , 0x82 , 0x01 , 0x0f , 0x00 ,
164
+ ] ;
165
+
166
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
167
+ const RSA_4096_ASN1_HEADER : [ u8 ; 24 ] = [
168
+ 0x30 , 0x82 , 0x02 , 0x22 , 0x30 , 0x0d , 0x06 , 0x09 , 0x2a , 0x86 , 0x48 , 0x86 , 0xf7 , 0x0d , 0x01 , 0x01 ,
169
+ 0x01 , 0x05 , 0x00 , 0x03 , 0x82 , 0x02 , 0x0f , 0x00 ,
170
+ ] ;
171
+
172
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
173
+ const EC_DSA_SECP_256_R1_ASN1_HEADER : [ u8 ; 26 ] = [
174
+ 0x30 , 0x59 , 0x30 , 0x13 , 0x06 , 0x07 , 0x2a , 0x86 , 0x48 , 0xce , 0x3d , 0x02 , 0x01 , 0x06 , 0x08 , 0x2a ,
175
+ 0x86 , 0x48 , 0xce , 0x3d , 0x03 , 0x01 , 0x07 , 0x03 , 0x42 , 0x00 ,
176
+ ] ;
177
+
178
+ #[ cfg( any( feature = "OSX_10_12" , target_os = "ios" ) ) ]
179
+ const EC_DSA_SECP_384_R1_ASN1_HEADER : [ u8 ; 23 ] = [
180
+ 0x30 , 0x76 , 0x30 , 0x10 , 0x06 , 0x07 , 0x2a , 0x86 , 0x48 , 0xce , 0x3d , 0x02 , 0x01 , 0x06 , 0x05 , 0x2b ,
181
+ 0x81 , 0x04 , 0x00 , 0x22 , 0x03 , 0x62 , 0x00 ,
182
+ ] ;
183
+
62
184
#[ cfg( test) ]
63
185
mod test {
64
186
use test:: certificate;
0 commit comments