@@ -47,17 +47,19 @@ import Data.X509.CertificateStore (CertificateStore,
47
47
makeCertificateStore )
48
48
import Data.X509.Validation
49
49
import Net.IP (IP )
50
+ import Net.IPv4 (IPv4 (.. ))
51
+ import Net.IPv6 (IPv6 (.. ))
52
+ import Network.Transport.Internal (encodeWord32 )
50
53
51
54
import qualified Crypto.PubKey.RSA.Types as RSA
52
55
import qualified Data.ByteString as BS
53
56
import qualified Data.ByteString.Base64 as Base64
57
+ import qualified Data.ByteString.Builder as BS
54
58
import qualified Data.ByteString.Char8 as B8
55
59
import qualified Data.ByteString.Lazy as BL
56
60
import qualified Data.Text as T
57
61
import qualified Data.Text.Encoding as T
58
62
import qualified Net.IP as IP
59
- import qualified Net.IPv4 as IPv4
60
- import qualified Net.IPv6 as IPv6
61
63
62
64
63
65
--
@@ -175,10 +177,34 @@ parseSAN :: String -> AltName
175
177
parseSAN name =
176
178
case IP. decode (toText name) of
177
179
Just ip ->
178
- AltNameIP . T. encodeUtf8 $ IP. case_ IPv4. encode IPv6. encode ip
180
+ AltNameIP $ IP. case_ ipv4ToBS ipv6ToBS ip
179
181
180
182
Nothing ->
181
183
AltNameDNS name
184
+ where
185
+ -- NOTE
186
+ -- Here, we define custom encoding functions and aren't using the ones
187
+ -- defined in `Net.IP`, `Net.IPv4` or `Net.IPv6`.
188
+ -- Those methods lead to invalid encodings for the underlying x509 certificates.
189
+ --
190
+ -- From the RFC 3779 (https://datatracker.ietf.org/doc/rfc3779):
191
+ --
192
+ -- > IP v4 address - a 32-bit identifier written as four decimal numbers,
193
+ -- > each in the range 0 to 255, separated by a ".". 10.5.0.5 is an
194
+ -- > example of an IPv4 address.
195
+ -- >
196
+ -- > IP v6 address - a 128-bit identifier written as eight hexadecimal
197
+ -- > quantities, each in the range 0 to ffff, separated by a ":".
198
+ -- > 2001:0:200:3:0:0:0:1 is an example of an IPv6 address. One string
199
+ -- > of :0: fields may be replaced by "::", thus 2001:0:200:3::1
200
+ -- > represents the same address as the immediately preceding example.
201
+ ipv4ToBS :: IPv4 -> ByteString
202
+ ipv4ToBS (IPv4 bytes) =
203
+ encodeWord32 bytes
204
+
205
+ ipv6ToBS :: IPv6 -> ByteString
206
+ ipv6ToBS (IPv6 a b) =
207
+ BL. toStrict $ BS. toLazyByteString (BS. word64BE a <> BS. word64BE b)
182
208
183
209
184
210
--
@@ -282,7 +308,7 @@ validateCertificateIP ip cert =
282
308
toCommonName =
283
309
asn1CharacterToString >=> (ipFromBytes . B8. pack)
284
310
in
285
- if any ( == ip) (maybeToList commonName ++ altNames) then
311
+ if ip `elem` (maybeToList commonName ++ altNames) then
286
312
[]
287
313
else
288
314
[NameMismatch $ T. unpack $ IP. encode ip]
0 commit comments