@@ -151,13 +151,31 @@ const ENCODE_CONFIG: pem::EncodeConfig = {
151
151
#[ non_exhaustive]
152
152
/// The type of subject alt name
153
153
pub enum SanType {
154
+ OtherName ( ( Vec < u64 > , OtherNameValue ) ) ,
154
155
/// Also known as E-Mail address
155
156
Rfc822Name ( Ia5String ) ,
156
157
DnsName ( Ia5String ) ,
157
158
URI ( Ia5String ) ,
158
159
IpAddress ( IpAddr ) ,
159
160
}
160
161
162
+ /// An other name entry
163
+ #[ derive( Debug , PartialEq , Eq , Hash , Clone ) ]
164
+ #[ non_exhaustive]
165
+ pub enum OtherNameValue {
166
+ /// A string encoded using UTF-8
167
+ Utf8String ( String ) ,
168
+ }
169
+
170
+ impl < T > From < T > for OtherNameValue
171
+ where
172
+ T : Into < String > ,
173
+ {
174
+ fn from ( t : T ) -> Self {
175
+ OtherNameValue :: Utf8String ( t. into ( ) )
176
+ }
177
+ }
178
+
161
179
#[ cfg( feature = "x509-parser" ) ]
162
180
fn ip_addr_from_octets ( octets : & [ u8 ] ) -> Result < IpAddr , Error > {
163
181
if let Ok ( ipv6_octets) = <& [ u8 ; 16 ] >:: try_from ( octets) {
@@ -172,7 +190,25 @@ fn ip_addr_from_octets(octets: &[u8]) -> Result<IpAddr, Error> {
172
190
impl SanType {
173
191
#[ cfg( feature = "x509-parser" ) ]
174
192
fn try_from_general ( name : & x509_parser:: extensions:: GeneralName < ' _ > ) -> Result < Self , Error > {
193
+ use x509_parser:: der_parser:: asn1_rs:: { self , FromDer , Tag , TaggedExplicit } ;
175
194
Ok ( match name {
195
+ x509_parser:: extensions:: GeneralName :: OtherName ( oid, value) => {
196
+ let oid = oid. iter ( ) . ok_or ( Error :: CouldNotParseCertificate ) ?;
197
+ // We first remove the explicit tag ([0] EXPLICIT)
198
+ let ( _, other_name) = TaggedExplicit :: < asn1_rs:: Any , _ , 0 > :: from_der ( & value)
199
+ . map_err ( |_| Error :: CouldNotParseCertificate ) ?;
200
+ let other_name = other_name. into_inner ( ) ;
201
+
202
+ let data = other_name. data ;
203
+ let try_str =
204
+ |data| std:: str:: from_utf8 ( data) . map_err ( |_| Error :: CouldNotParseCertificate ) ;
205
+ let other_name_value = match other_name. tag ( ) {
206
+ Tag :: Utf8String => OtherNameValue :: Utf8String ( try_str ( data) ?. to_owned ( ) ) ,
207
+ _ => return Err ( Error :: CouldNotParseCertificate ) ,
208
+ } ;
209
+
210
+ SanType :: OtherName ( ( oid. collect ( ) , other_name_value) )
211
+ } ,
176
212
x509_parser:: extensions:: GeneralName :: RFC822Name ( name) => {
177
213
SanType :: Rfc822Name ( ( * name) . try_into ( ) ?)
178
214
} ,
@@ -190,12 +226,14 @@ impl SanType {
190
226
fn tag ( & self ) -> u64 {
191
227
// Defined in the GeneralName list in
192
228
// https://tools.ietf.org/html/rfc5280#page-38
229
+ const TAG_OTHER_NAME : u64 = 0 ;
193
230
const TAG_RFC822_NAME : u64 = 1 ;
194
231
const TAG_DNS_NAME : u64 = 2 ;
195
232
const TAG_URI : u64 = 6 ;
196
233
const TAG_IP_ADDRESS : u64 = 7 ;
197
234
198
235
match self {
236
+ Self :: OtherName ( _oid) => TAG_OTHER_NAME ,
199
237
SanType :: Rfc822Name ( _name) => TAG_RFC822_NAME ,
200
238
SanType :: DnsName ( _name) => TAG_DNS_NAME ,
201
239
SanType :: URI ( _name) => TAG_URI ,
@@ -856,6 +894,22 @@ impl CertificateParams {
856
894
writer. next ( ) . write_tagged_implicit (
857
895
Tag :: context ( san. tag ( ) ) ,
858
896
|writer| match san {
897
+ SanType :: OtherName ( ( oid, value) ) => {
898
+ // otherName SEQUENCE { OID, [0] explicit any defined by oid }
899
+ // https://datatracker.ietf.org/doc/html/rfc5280#page-38
900
+ let oid = ObjectIdentifier :: from_slice ( & oid) ;
901
+ writer. write_sequence ( |writer| {
902
+ writer. next ( ) . write_oid ( & oid) ;
903
+ writer. next ( ) . write_tagged (
904
+ Tag :: context ( 0 ) ,
905
+ |writer| match value {
906
+ OtherNameValue :: Utf8String ( s) => {
907
+ writer. write_utf8_string ( s)
908
+ } ,
909
+ } ,
910
+ ) ;
911
+ } ) ;
912
+ } ,
859
913
SanType :: Rfc822Name ( name)
860
914
| SanType :: DnsName ( name)
861
915
| SanType :: URI ( name) => writer. write_ia5_string ( name. as_str ( ) ) ,
0 commit comments