@@ -24,7 +24,7 @@ use alloc::string::String;
2424/// allowed.
2525///
2626/// `DnsName` stores a copy of the input it was constructed from in a `String`
27- /// and so it is only available when the `std ` default feature is enabled.
27+ /// and so it is only available when the `alloc ` default feature is enabled.
2828///
2929/// `Eq`, `PartialEq`, etc. are not implemented because name comparison
3030/// frequently should be done case-insensitively and/or with other caveats that
@@ -147,6 +147,123 @@ impl<'a> From<DnsNameRef<'a>> for &'a str {
147147 }
148148}
149149
150+ /// A DNS Name suitable for use in the TLS Server Name Indication (SNI)
151+ /// extension and/or for use as the reference hostname for which to verify a
152+ /// certificate.
153+ pub enum GeneralDnsNameRef < ' name > {
154+ /// a valid DNS name
155+ DnsName ( DnsNameRef < ' name > ) ,
156+ /// a DNS name containing a wildcard
157+ Wildcard ( WildcardDnsNameRef < ' name > ) ,
158+ }
159+
160+ impl < ' a > From < GeneralDnsNameRef < ' a > > for & ' a str {
161+ fn from ( d : GeneralDnsNameRef < ' a > ) -> Self {
162+ match d {
163+ GeneralDnsNameRef :: DnsName ( name) => name. into ( ) ,
164+ GeneralDnsNameRef :: Wildcard ( name) => name. into ( ) ,
165+ }
166+ }
167+ }
168+
169+ /// A reference to a DNS Name suitable for use in the TLS Server Name Indication
170+ /// (SNI) extension and/or for use as the reference hostname for which to verify
171+ /// a certificate. Compared to `DnsName`, this one will store domain names containing
172+ /// a wildcard.
173+ ///
174+ /// A `WildcardDnsName` is guaranteed to be syntactically valid. The validity rules are
175+ /// specified in [RFC 5280 Section 7.2], except that underscores are also
176+ /// allowed, and following [RFC 6125].
177+ ///
178+ /// `WildcardDnsName` stores a copy of the input it was constructed from in a `String`
179+ /// and so it is only available when the `alloc` default feature is enabled.
180+ ///
181+ /// `Eq`, `PartialEq`, etc. are not implemented because name comparison
182+ /// frequently should be done case-insensitively and/or with other caveats that
183+ /// depend on the specific circumstances in which the comparison is done.
184+ ///
185+ /// [RFC 5280 Section 7.2]: https://tools.ietf.org/html/rfc5280#section-7.2
186+ /// [RFC 6125]: https://tools.ietf.org/html/rfc6125
187+ #[ cfg( feature = "alloc" ) ]
188+ #[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
189+ pub struct WildcardDnsName ( String ) ;
190+
191+ #[ cfg( feature = "alloc" ) ]
192+ impl WildcardDnsName {
193+ /// Returns a `WildcardDnsNameRef` that refers to this `WildcardDnsName`.
194+ pub fn as_ref ( & self ) -> WildcardDnsNameRef { WildcardDnsNameRef ( self . 0 . as_bytes ( ) ) }
195+ }
196+
197+ #[ cfg( feature = "alloc" ) ]
198+ impl AsRef < str > for WildcardDnsName {
199+ fn as_ref ( & self ) -> & str { self . 0 . as_ref ( ) }
200+ }
201+
202+ // Deprecated
203+ #[ cfg( feature = "alloc" ) ]
204+ impl From < WildcardDnsNameRef < ' _ > > for WildcardDnsName {
205+ fn from ( dns_name : WildcardDnsNameRef ) -> Self { dns_name. to_owned ( ) }
206+ }
207+
208+ /// A reference to a DNS Name suitable for use in the TLS Server Name Indication
209+ /// (SNI) extension and/or for use as the reference hostname for which to verify
210+ /// a certificate.
211+ ///
212+ /// A `WildcardDnsNameRef` is guaranteed to be syntactically valid. The validity rules
213+ /// are specified in [RFC 5280 Section 7.2], except that underscores are also
214+ /// allowed.
215+ ///
216+ /// `Eq`, `PartialEq`, etc. are not implemented because name comparison
217+ /// frequently should be done case-insensitively and/or with other caveats that
218+ /// depend on the specific circumstances in which the comparison is done.
219+ ///
220+ /// [RFC 5280 Section 7.2]: https://tools.ietf.org/html/rfc5280#section-7.2
221+ #[ derive( Clone , Copy ) ]
222+ pub struct WildcardDnsNameRef < ' a > ( & ' a [ u8 ] ) ;
223+
224+ impl < ' a > WildcardDnsNameRef < ' a > {
225+ /// Constructs a `WildcardDnsNameRef` from the given input if the input is a
226+ /// syntactically-valid DNS name.
227+ pub fn try_from_ascii ( dns_name : & ' a [ u8 ] ) -> Result < Self , InvalidDnsNameError > {
228+ if !is_valid_wildcard_dns_id ( untrusted:: Input :: from ( dns_name) ) {
229+ return Err ( InvalidDnsNameError ) ;
230+ }
231+
232+ Ok ( Self ( dns_name) )
233+ }
234+
235+ /// Constructs a `WildcardDnsNameRef` from the given input if the input is a
236+ /// syntactically-valid DNS name.
237+ pub fn try_from_ascii_str ( dns_name : & ' a str ) -> Result < Self , InvalidDnsNameError > {
238+ Self :: try_from_ascii ( dns_name. as_bytes ( ) )
239+ }
240+
241+ /// Constructs a `WildcardDnsName` from this `WildcardDnsNameRef`
242+ #[ cfg( feature = "alloc" ) ]
243+ pub fn to_owned ( & self ) -> WildcardDnsName {
244+ // WildcardDnsNameRef is already guaranteed to be valid ASCII, which is a
245+ // subset of UTF-8.
246+ let s: & str = self . clone ( ) . into ( ) ;
247+ WildcardDnsName ( s. to_ascii_lowercase ( ) )
248+ }
249+ }
250+
251+ #[ cfg( feature = "alloc" ) ]
252+ impl core:: fmt:: Debug for WildcardDnsNameRef < ' _ > {
253+ fn fmt ( & self , f : & mut core:: fmt:: Formatter ) -> Result < ( ) , core:: fmt:: Error > {
254+ let lowercase = self . clone ( ) . to_owned ( ) ;
255+ f. debug_tuple ( "WildcardDnsNameRef" ) . field ( & lowercase. 0 ) . finish ( )
256+ }
257+ }
258+
259+ impl < ' a > From < WildcardDnsNameRef < ' a > > for & ' a str {
260+ fn from ( WildcardDnsNameRef ( d) : WildcardDnsNameRef < ' a > ) -> Self {
261+ // The unwrap won't fail because DnsNameRefs are guaranteed to be ASCII
262+ // and ASCII is a subset of UTF-8.
263+ core:: str:: from_utf8 ( d) . unwrap ( )
264+ }
265+ }
266+
150267pub ( super ) fn presented_id_matches_reference_id (
151268 presented_dns_id : untrusted:: Input ,
152269 reference_dns_id : untrusted:: Input ,
@@ -577,6 +694,10 @@ fn is_valid_dns_id(
577694 true
578695}
579696
697+ fn is_valid_wildcard_dns_id ( hostname : untrusted:: Input ) -> bool {
698+ is_valid_dns_id ( hostname, IDRole :: ReferenceID , AllowWildcards :: Yes )
699+ }
700+
580701#[ cfg( test) ]
581702mod tests {
582703 use super :: * ;
0 commit comments