@@ -149,13 +149,41 @@ const ENCODE_CONFIG: pem::EncodeConfig = {
149
149
#[ non_exhaustive]
150
150
/// The type of subject alt name
151
151
pub enum SanType {
152
+ OtherName ( ( Vec < u64 > , OtherNameValue ) ) ,
152
153
/// Also known as E-Mail address
153
154
Rfc822Name ( String ) ,
154
155
DnsName ( String ) ,
155
156
URI ( String ) ,
156
157
IpAddress ( IpAddr ) ,
157
158
}
158
159
160
+ /// An other name entry
161
+ #[ derive( Debug , PartialEq , Eq , Hash , Clone ) ]
162
+ #[ non_exhaustive]
163
+ pub enum OtherNameValue {
164
+ /// A string encoded using UCS-2
165
+ BmpString ( Vec < u8 > ) ,
166
+ /// An ASCII string.
167
+ Ia5String ( String ) ,
168
+ /// An ASCII string containing only A-Z, a-z, 0-9, '()+,-./:=? and `<SPACE>`
169
+ PrintableString ( String ) ,
170
+ /// A string of characters from the T.61 character set
171
+ TeletexString ( Vec < u8 > ) ,
172
+ /// A string encoded using UTF-32
173
+ UniversalString ( Vec < u8 > ) ,
174
+ /// A string encoded using UTF-8
175
+ Utf8String ( String ) ,
176
+ }
177
+
178
+ impl < T > From < T > for OtherNameValue
179
+ where
180
+ T : Into < String > ,
181
+ {
182
+ fn from ( t : T ) -> Self {
183
+ OtherNameValue :: Utf8String ( t. into ( ) )
184
+ }
185
+ }
186
+
159
187
#[ cfg( feature = "x509-parser" ) ]
160
188
fn ip_addr_from_octets ( octets : & [ u8 ] ) -> Result < IpAddr , Error > {
161
189
if let Ok ( ipv6_octets) = <& [ u8 ; 16 ] >:: try_from ( octets) {
@@ -170,7 +198,32 @@ fn ip_addr_from_octets(octets: &[u8]) -> Result<IpAddr, Error> {
170
198
impl SanType {
171
199
#[ cfg( feature = "x509-parser" ) ]
172
200
fn try_from_general ( name : & x509_parser:: extensions:: GeneralName < ' _ > ) -> Result < Self , Error > {
201
+ use x509_parser:: der_parser:: asn1_rs:: { self , FromDer , Tag , TaggedExplicit } ;
173
202
Ok ( match name {
203
+ x509_parser:: extensions:: GeneralName :: OtherName ( oid, value) => {
204
+ let oid = oid. iter ( ) . ok_or ( Error :: CouldNotParseCertificate ) ?;
205
+ // We first remove the explicit tag ([0] EXPLICIT)
206
+ let ( _, other_name) = TaggedExplicit :: < asn1_rs:: Any , _ , 0 > :: from_der ( & value)
207
+ . map_err ( |_| Error :: CouldNotParseCertificate ) ?;
208
+ let other_name = other_name. into_inner ( ) ;
209
+
210
+ let data = other_name. data ;
211
+ let try_str =
212
+ |data| std:: str:: from_utf8 ( data) . map_err ( |_| Error :: CouldNotParseCertificate ) ;
213
+ let other_name_value = match other_name. tag ( ) {
214
+ Tag :: BmpString => OtherNameValue :: BmpString ( data. into ( ) ) ,
215
+ Tag :: Ia5String => OtherNameValue :: Ia5String ( try_str ( data) ?. to_owned ( ) ) ,
216
+ Tag :: PrintableString => {
217
+ OtherNameValue :: PrintableString ( try_str ( data) ?. to_owned ( ) )
218
+ } ,
219
+ Tag :: T61String => OtherNameValue :: TeletexString ( data. into ( ) ) ,
220
+ Tag :: UniversalString => OtherNameValue :: UniversalString ( data. into ( ) ) ,
221
+ Tag :: Utf8String => OtherNameValue :: Utf8String ( try_str ( data) ?. to_owned ( ) ) ,
222
+ _ => return Err ( Error :: CouldNotParseCertificate ) ,
223
+ } ;
224
+
225
+ SanType :: OtherName ( ( oid. collect ( ) , other_name_value) )
226
+ } ,
174
227
x509_parser:: extensions:: GeneralName :: RFC822Name ( name) => {
175
228
SanType :: Rfc822Name ( ( * name) . into ( ) )
176
229
} ,
@@ -186,12 +239,14 @@ impl SanType {
186
239
fn tag ( & self ) -> u64 {
187
240
// Defined in the GeneralName list in
188
241
// https://tools.ietf.org/html/rfc5280#page-38
242
+ const TAG_OTHER_NAME : u64 = 0 ;
189
243
const TAG_RFC822_NAME : u64 = 1 ;
190
244
const TAG_DNS_NAME : u64 = 2 ;
191
245
const TAG_URI : u64 = 6 ;
192
246
const TAG_IP_ADDRESS : u64 = 7 ;
193
247
194
248
match self {
249
+ Self :: OtherName ( _oid) => TAG_OTHER_NAME ,
195
250
SanType :: Rfc822Name ( _name) => TAG_RFC822_NAME ,
196
251
SanType :: DnsName ( _name) => TAG_DNS_NAME ,
197
252
SanType :: URI ( _name) => TAG_URI ,
@@ -848,6 +903,42 @@ impl CertificateParams {
848
903
writer. next ( ) . write_tagged_implicit (
849
904
Tag :: context ( san. tag ( ) ) ,
850
905
|writer| match san {
906
+ SanType :: OtherName ( ( oid, value) ) => {
907
+ // otherName SEQUENCE { OID, [0] explicit any defined by oid }
908
+ // https://datatracker.ietf.org/doc/html/rfc5280#page-38
909
+ let oid = ObjectIdentifier :: from_slice ( & oid) ;
910
+ writer. write_sequence ( |writer| {
911
+ writer. next ( ) . write_oid ( & oid) ;
912
+ writer. next ( ) . write_tagged (
913
+ Tag :: context ( 0 ) ,
914
+ |writer| match value {
915
+ OtherNameValue :: BmpString ( s) => writer
916
+ . write_tagged_implicit ( TAG_BMPSTRING , |writer| {
917
+ writer. write_bytes ( s)
918
+ } ) ,
919
+ OtherNameValue :: Ia5String ( s) => {
920
+ writer. write_ia5_string ( s)
921
+ } ,
922
+ OtherNameValue :: PrintableString ( s) => {
923
+ writer. write_printable_string ( s)
924
+ } ,
925
+ OtherNameValue :: TeletexString ( s) => writer
926
+ . write_tagged_implicit (
927
+ TAG_TELETEXSTRING ,
928
+ |writer| writer. write_bytes ( s) ,
929
+ ) ,
930
+ OtherNameValue :: UniversalString ( s) => writer
931
+ . write_tagged_implicit (
932
+ TAG_UNIVERSALSTRING ,
933
+ |writer| writer. write_bytes ( s) ,
934
+ ) ,
935
+ OtherNameValue :: Utf8String ( s) => {
936
+ writer. write_utf8_string ( s)
937
+ } ,
938
+ } ,
939
+ ) ;
940
+ } ) ;
941
+ } ,
851
942
SanType :: Rfc822Name ( name)
852
943
| SanType :: DnsName ( name)
853
944
| SanType :: URI ( name) => writer. write_ia5_string ( name) ,
0 commit comments