Use the idiom below to import Crypto.Random, due to a bug in iHaskell with the extension PackageImports
In [21]:
:ext OverloadedStrings
:!rm himports.hs
:!echo "{-# LANGUAGE PackageImports #-}" >> himports.hs
:!echo "module MouseBoxImports( module Crypto.Random ) where" >> himports.hs
:!echo "import \"crypto-api\" Crypto.Random" >> himports.hs
:load himports
In [22]:
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as LB
In [23]:
import Codec.Crypto.RSA.Pure
In [24]:
g <- newGenIO :: IO SystemRandom
In [25]:
:info SystemRandom
In [26]:
let Right (public_key, private_key, g') = generateKeyPair g 2048
In [27]:
let Codec.Crypto.RSA.Pure.PublicKey public_size public_n public_e = public_key
In [28]:
import Data.X509
import Data.ASN1.OID
import Data.ASN1.Types.String
import Data.Hourglass.Types
import Crypto.PubKey.RSA.Types
import qualified Data.Binary as Bn
In [29]:
stringize :: B.ByteString -> ASN1CharacterString
stringize s = ASN1CharacterString IA5 s
In [30]:
:type PubKeyRSA $ Crypto.PubKey.RSA.Types.PublicKey public_size public_n public_e
In [31]:
pubkeyToAlg . PubKeyRSA $ Crypto.PubKey.RSA.Types.PublicKey public_size public_n public_e
In [32]:
publicKeyHasher :: Codec.Crypto.RSA.Pure.PublicKey -> B.ByteString
publicKeyHasher pk = LB.toStrict . LB.take 20 . Bn.encode $ pk
In [33]:
let
ca_common_name = "MouseBox Testing Cert. Authority # affewx "
pubkey_to_use = PubKeyRSA $ Crypto.PubKey.RSA.Types.PublicKey public_size public_n public_e
ca_dn = DistinguishedName [
(getObjectID DnCommonName, stringize ca_common_name),
(getObjectID DnCountry, stringize "SE"),
(getObjectID DnOrganization, stringize "MouseBox by Zunzun AB"),
(getObjectID DnOrganizationUnit, stringize "Testing")
]
a_cert = Certificate {
certVersion = 2 -- There are three different versions of X.509.
-- The certificate has to claim what version it uses.
-- So you'll find this Version: field in the certificate.
-- The most recent version is 3 and this is the most used version.
-- X.509 version 3 defines extensions.
-- So for example, they are used for certificate chains.
, certSerial = 1
, certSignatureAlg = SignatureALG HashSHA384 (pubkeyToAlg pubkey_to_use)
, certIssuerDN = ca_dn
, certValidity = (
DateTime {dtDate = Date 2015 January 1, dtTime = TimeOfDay 0 0 0 0},
DateTime {dtDate = Date 2025 December 31, dtTime = TimeOfDay 23 59 0 0}
)
, certSubjectDN = ca_dn
, certPubKey = PubKeyRSA $ Crypto.PubKey.RSA.Types.PublicKey public_size public_n public_e
-- TODO: We need to set a few extensions here....
, certExtensions = Extensions (Just
-- The set of extensions below is specific to CAs
[
extensionEncode True {-Critical-} (ExtKeyUsage [KeyUsage_keyCertSign]),
extensionEncode True (ExtBasicConstraints True
-- The field below says that leaf certificates must be signed by this one.
-- A little bit in the way of extra-security...
(Just 0)
),
extensionEncode True (ExtSubjectKeyId . publicKeyHasher $ public_key )
]
)
}
In [34]:
hereSign :: B.ByteString -> (B.ByteString, SignatureALG, ())
hereSign stuff_to_sign = let
Right bs_sign = rsassa_pkcs1_v1_5_sign hashSHA384 private_key . LB.fromStrict $ stuff_to_sign
in (LB.toStrict bs_sign, SignatureALG HashSHA384 PubKeyALG_RSA, () )
In [35]:
let (signed_exact_obj, _) = objectToSignedExact hereSign a_cert
In [36]:
B.writeFile "a_cert.der" $ encodeSignedObject signed_exact_obj
In [37]:
import Data.PEM
In [38]:
let
pem_formatted = PEM {
pemName = "CERTIFICATE",
pemHeader = [],
pemContent = encodeSignedObject signed_exact_obj
}
B.writeFile "a_cert.pem" . pemWriteBS $ pem_formatted
In [39]:
:!openssl verify -check_ss_sig -trusted a_cert.pem a_cert.pem
In [ ]: