@@ -28,13 +28,13 @@ extension RelativeDistinguishedName {
28
28
public struct Attribute {
29
29
public struct Value : Hashable , Sendable {
30
30
@usableFromInline
31
- enum Storage : Sendable {
31
+ enum Storage : Hashable , Sendable {
32
32
/// ``ASN1PrintableString``
33
33
case printable( String )
34
34
/// ``ASN1UTF8String``
35
35
case utf8( String )
36
- /// `.any` can still contain bytes which are equal to the DER representation of `.printable` or `.utf8`
37
- /// the custom `Hashable` conformance takes care of this and treats them as equal .
36
+ /// `.any` can never contain bytes which are equal to the DER representation of `.printable` or `.utf8`.
37
+ /// This invariant must not be violated or otherwise the synthesised `Hashable` would be wrong .
38
38
case any( ASN1Any )
39
39
}
40
40
@@ -66,172 +66,6 @@ extension RelativeDistinguishedName {
66
66
}
67
67
}
68
68
69
- extension RelativeDistinguishedName . Attribute . Value . Storage : Hashable {
70
- @inlinable
71
- static func == ( lhs: Self , rhs: Self ) -> Bool {
72
- switch ( lhs, rhs) {
73
- case let ( . printable( lhs) , . printable( rhs) ) :
74
- return lhs == rhs
75
- case let ( . utf8( lhs) , . utf8( rhs) ) :
76
- return lhs == rhs
77
- case ( . printable, . utf8) , ( . utf8, . printable) :
78
- return false
79
-
80
- default :
81
- return ASN1Any ( lhs) == ASN1Any ( rhs)
82
- }
83
- }
84
-
85
- @inlinable
86
- func hash( into hasher: inout Hasher ) {
87
- switch self {
88
- case . printable( let string) :
89
- hasher. combine ( String . ASN1TaggedStringView ( printable: string) )
90
-
91
- case . utf8( let string) :
92
- hasher. combine ( String . ASN1TaggedStringView ( utf8: string) )
93
-
94
- case . any( let asn1Any) :
95
- hasher. combine ( asn1Any)
96
- }
97
- }
98
- }
99
-
100
- extension String {
101
- @usableFromInline
102
- struct ASN1TaggedStringView {
103
- @usableFromInline
104
- let tag : UInt8
105
-
106
- @usableFromInline
107
- let string : String
108
-
109
- @usableFromInline
110
- let length : ASN1Length
111
-
112
- @usableFromInline
113
- let count : Int
114
-
115
- @inlinable
116
- init ( tag: UInt8 , string: String ) {
117
- self . tag = tag
118
- self . string = string
119
-
120
- let utf8Count = self . string. utf8. count
121
- self . length = ASN1Length ( length: utf8Count)
122
- // tag + utf8 bytes length + utf8 bytes
123
- self . count = 1 + self . length. count + utf8Count
124
- }
125
-
126
- @inlinable
127
- init ( utf8 string: String ) {
128
- // This tag represents a UTF8STRING.
129
- self . init ( tag: 0x0c , string: string)
130
- }
131
-
132
- @inlinable
133
- init ( printable string: String ) {
134
- // This tag represents a PRINTABLE STRING.
135
- self . init ( tag: 0x13 , string: string)
136
- }
137
- }
138
- }
139
-
140
- extension String . ASN1TaggedStringView : RandomAccessCollection {
141
- @inlinable
142
- var startIndex : Int {
143
- 0
144
- }
145
-
146
- @inlinable
147
- var endIndex : Int {
148
- count
149
- }
150
-
151
- @inlinable
152
- subscript( position: Int ) -> UInt8 {
153
- switch position {
154
- case 0 :
155
- return self . tag
156
- case 1 ... self . length. endIndex:
157
- // after the tag comes the length of the string
158
- return self . length [ position &- 1 ]
159
- default :
160
- // and at the end the utf8 encoded string
161
- let index = self . string. utf8. index ( self . string. utf8. startIndex, offsetBy: position - 1 - length. endIndex)
162
- return self . string. utf8 [ index]
163
- }
164
- }
165
- }
166
-
167
- extension String . ASN1TaggedStringView : Hashable {
168
- @inlinable
169
- func hash( into hasher: inout Hasher ) {
170
- hasher. combine ( self . count)
171
- for byte in self {
172
- hasher. combine ( byte)
173
- }
174
- }
175
- }
176
-
177
- @usableFromInline
178
- struct ASN1Length : Hashable {
179
- @usableFromInline
180
- var length : Int
181
-
182
- @usableFromInline
183
- var count : Int
184
-
185
- @inlinable
186
- init ( length: Int ) {
187
- self . length = length
188
-
189
- // ASN.1 lengths are in two forms. If we can store the length in 7 bits, we should:
190
- // that requires only one byte. Otherwise, we need multiple bytes: work out how many,
191
- // plus one for the length of the length bytes.
192
- if self . length <= 0x7F {
193
- self . count = 1
194
- } else {
195
- // We need to work out how many bytes we need. There are many fancy bit-twiddling
196
- // ways of doing this, but honestly we don't do this enough to need them, so we'll
197
- // do it the easy way. This math is done on UInt because it makes the shift semantics clean.
198
- // We save a branch here because we can never overflow this addition.
199
- let neededBits = self . length. bitWidth - self . length. leadingZeroBitCount
200
- let neededBytes = ( neededBits &+ 7 ) / 8
201
- self . count = neededBytes &+ 1
202
- }
203
- }
204
- }
205
-
206
- extension ASN1Length : RandomAccessCollection {
207
- @inlinable
208
- var startIndex : Int {
209
- 0
210
- }
211
-
212
- @inlinable
213
- var endIndex : Int {
214
- count
215
- }
216
-
217
- @inlinable
218
- subscript( position: Int ) -> UInt8 {
219
- precondition ( position >= 0 && position < self . count)
220
- guard self . length <= 0x7F else {
221
- guard position == 0 else {
222
- //Then we write the bytes of the length.
223
- let integerBytesCollection = IntegerBytesCollection ( self . length)
224
- let index = integerBytesCollection. index ( integerBytesCollection. startIndex, offsetBy: position &- 1 )
225
- return integerBytesCollection [ index]
226
- }
227
- // We first write the number of length bytes
228
- // we needed, setting the high bit.
229
- return 0b1000_0000 | UInt8 ( self . count &- 1 )
230
- }
231
- return UInt8 ( truncatingIfNeeded: self . length)
232
- }
233
- }
234
-
235
69
extension ASN1Any {
236
70
@inlinable
237
71
init ( _ storage: RelativeDistinguishedName . Attribute . Value . Storage ) {
@@ -274,7 +108,40 @@ extension RelativeDistinguishedName.Attribute.Value {
274
108
275
109
@inlinable
276
110
public init ( asn1Any: ASN1Any ) {
277
- self . storage = . any( asn1Any)
111
+ do {
112
+ self . storage = try . init( asn1Any: asn1Any)
113
+ } catch {
114
+ self . storage = . any( asn1Any)
115
+ }
116
+ }
117
+ }
118
+
119
+ extension RelativeDistinguishedName . Attribute . Value . Storage : DERParseable , DERSerializable {
120
+ @inlinable
121
+ init ( derEncoded node: SwiftASN1 . ASN1Node ) throws {
122
+ switch node. identifier {
123
+ case ASN1UTF8String . defaultIdentifier:
124
+ self = . utf8( String ( try ASN1UTF8String ( derEncoded: node) ) )
125
+ case ASN1PrintableString . defaultIdentifier:
126
+ self = . printable( String ( try ASN1PrintableString ( derEncoded: node) ) )
127
+ default :
128
+ self = . any( ASN1Any ( derEncoded: node) )
129
+ }
130
+ }
131
+
132
+ @inlinable
133
+ func serialize( into coder: inout SwiftASN1 . DER . Serializer ) throws {
134
+ switch self {
135
+ case . printable( let printableString) :
136
+ // force try is safe because we verify in the initialiser that it is valid
137
+ let printableString = try ! ASN1PrintableString ( printableString)
138
+ try printableString. serialize ( into: & coder)
139
+ case . utf8( let utf8String) :
140
+ let string = ASN1UTF8String ( utf8String)
141
+ try string. serialize ( into: & coder)
142
+ case . any( let any) :
143
+ try any. serialize ( into: & coder)
144
+ }
278
145
}
279
146
}
280
147
@@ -376,132 +243,7 @@ extension RelativeDistinguishedName.Attribute: DERImplicitlyTaggable {
376
243
public init ( derEncoded rootNode: ASN1Node , withIdentifier identifier: ASN1Identifier ) throws {
377
244
self = try DER . sequence ( rootNode, identifier: identifier) { nodes in
378
245
let type = try ASN1ObjectIdentifier ( derEncoded: & nodes)
379
- guard let valueNode = nodes. next ( ) else {
380
- throw ASN1Error . invalidASN1Object ( reason: " RelativeDistinguishedName.Attribute.Value is missing " )
381
- }
382
-
383
- let value : Value
384
- switch type {
385
- /// ```
386
- /// id-at-commonName AttributeType ::= { id-at 3 }
387
- ///
388
- /// -- Naming attributes of type X520CommonName:
389
- /// -- X520CommonName ::= DirectoryName (SIZE (1..ub-common-name))
390
- /// --
391
- /// -- Expanded to avoid parameterized type:
392
- /// X520CommonName ::= CHOICE {
393
- /// teletexString TeletexString (SIZE (1..ub-common-name)),
394
- /// printableString PrintableString (SIZE (1..ub-common-name)),
395
- /// universalString UniversalString (SIZE (1..ub-common-name)),
396
- /// utf8String UTF8String (SIZE (1..ub-common-name)),
397
- /// bmpString BMPString (SIZE (1..ub-common-name)) }
398
- ///
399
- ///
400
- /// -- Naming attributes of type X520LocalityName
401
- ///
402
- /// id-at-localityName AttributeType ::= { id-at 7 }
403
- ///
404
- /// -- Naming attributes of type X520LocalityName:
405
- /// -- X520LocalityName ::= DirectoryName (SIZE (1..ub-locality-name))
406
- /// --
407
- /// -- Expanded to avoid parameterized type:
408
- /// X520LocalityName ::= CHOICE {
409
- /// teletexString TeletexString (SIZE (1..ub-locality-name)),
410
- /// printableString PrintableString (SIZE (1..ub-locality-name)),
411
- /// universalString UniversalString (SIZE (1..ub-locality-name)),
412
- /// utf8String UTF8String (SIZE (1..ub-locality-name)),
413
- /// bmpString BMPString (SIZE (1..ub-locality-
414
- ///
415
- /// id-at-stateOrProvinceName AttributeType ::= { id-at 8 }
416
- ///
417
- ///
418
- /// -- Naming attributes of type X520StateOrProvinceName:
419
- /// -- X520StateOrProvinceName ::= DirectoryName (SIZE (1..ub-state-name))
420
- /// --
421
- /// -- Expanded to avoid parameterized type:
422
- /// X520StateOrProvinceName ::= CHOICE {
423
- /// teletexString TeletexString (SIZE (1..ub-state-name)),
424
- /// printableString PrintableString (SIZE (1..ub-state-name)),
425
- /// universalString UniversalString (SIZE (1..ub-state-name)),
426
- /// utf8String UTF8String (SIZE (1..ub-state-name)),
427
- /// bmpString BMPString (SIZE (1..ub-state-name)) }
428
- ///
429
- ///
430
- /// -- Naming attributes of type X520OrganizationName
431
- ///
432
- /// id-at-organizationName AttributeType ::= { id-at 10 }
433
- ///
434
- /// -- Naming attributes of type X520OrganizationName:
435
- /// -- X520OrganizationName ::=
436
- /// -- DirectoryName (SIZE (1..ub-organization-name))
437
- /// --
438
- /// -- Expanded to avoid parameterized type:
439
- /// X520OrganizationName ::= CHOICE {
440
- /// teletexString TeletexString
441
- /// (SIZE (1..ub-organization-name)),
442
- /// printableString PrintableString
443
- /// (SIZE (1..ub-organization-name)),
444
- /// universalString UniversalString
445
- /// (SIZE (1..ub-organization-name)),
446
- /// utf8String UTF8String
447
- /// (SIZE (1..ub-organization-name)),
448
- /// bmpString BMPString
449
- /// (SIZE (1..ub-organization-name)) }
450
- ///
451
- ///
452
- /// id-at-organizationalUnitName AttributeType ::= { id-at 11 }
453
- ///
454
- /// -- Naming attributes of type X520OrganizationalUnitName:
455
- /// -- X520OrganizationalUnitName ::=
456
- /// -- DirectoryName (SIZE (1..ub-organizational-unit-name))
457
- /// --
458
- /// -- Expanded to avoid parameterized type:
459
- /// X520OrganizationalUnitName ::= CHOICE {
460
- /// teletexString TeletexString
461
- /// (SIZE (1..ub-organizational-unit-name)),
462
- /// printableString PrintableString
463
- /// (SIZE (1..ub-organizational-unit-name)),
464
- /// universalString UniversalString
465
- /// (SIZE (1..ub-organizational-unit-name)),
466
- /// utf8String UTF8String
467
- /// (SIZE (1..ub-organizational-unit-name)),
468
- /// bmpString BMPString
469
- /// (SIZE (1..ub-organizational-unit-name)) }
470
- /// ```
471
- case . RDNAttributeType. commonName,
472
- . RDNAttributeType. localityName,
473
- . RDNAttributeType. stateOrProvinceName,
474
- . RDNAttributeType. organizationName,
475
- . RDNAttributeType. organizationalUnitName:
476
-
477
- switch valueNode. identifier {
478
- case ASN1UTF8String . defaultIdentifier:
479
- value = try . init( utf8String: String ( ASN1UTF8String ( derEncoded: valueNode) ) )
480
- case ASN1PrintableString . defaultIdentifier:
481
- value = try . init( printableString: String ( ASN1PrintableString ( derEncoded: valueNode) ) )
482
- default :
483
- value = . init( storage: . any( ASN1Any ( derEncoded: valueNode) ) )
484
- }
485
-
486
- /// ```
487
- /// -- Naming attributes of type X520countryName (digraph from IS 3166)
488
- ///
489
- /// id-at-countryName AttributeType ::= { id-at 6 }
490
- ///
491
- /// X520countryName ::= PrintableString (SIZE (2))
492
- /// ```
493
- case . RDNAttributeType. countryName:
494
- switch valueNode. identifier {
495
- case ASN1PrintableString . defaultIdentifier:
496
- value = try . init( printableString: String ( ASN1PrintableString ( derEncoded: valueNode) ) )
497
- default :
498
- value = . init( storage: . any( ASN1Any ( derEncoded: valueNode) ) )
499
- }
500
-
501
- default:
502
- value = . init( storage: . any( ASN1Any ( derEncoded: valueNode) ) )
503
- }
504
-
246
+ let value = try Value ( storage: . init( derEncoded: & nodes) )
505
247
return . init( type: type, value: value)
506
248
}
507
249
}
@@ -510,7 +252,7 @@ extension RelativeDistinguishedName.Attribute: DERImplicitlyTaggable {
510
252
public func serialize( into coder: inout DER . Serializer , withIdentifier identifier: ASN1Identifier ) throws {
511
253
try coder. appendConstructedNode ( identifier: identifier) { coder in
512
254
try coder. serialize ( self . type)
513
- try coder. serialize ( ASN1Any ( self . value) )
255
+ try coder. serialize ( self . value. storage )
514
256
}
515
257
}
516
258
}
@@ -594,7 +336,7 @@ extension String {
594
336
self = printable
595
337
case . utf8( let utf8) :
596
338
self = utf8
597
- default :
339
+ case . any :
598
340
return nil
599
341
}
600
342
}
0 commit comments