|
| 1 | +module Node.Crypto.KeyObject |
| 2 | + ( KeyObjectType |
| 3 | + , Symmetric |
| 4 | + , Asymmetric |
| 5 | + , AsymmetricKeyType |
| 6 | + , Private |
| 7 | + , Public |
| 8 | + , KeyObject |
| 9 | + , KeyFormat |
| 10 | + , pem |
| 11 | + , der |
| 12 | + , jwk |
| 13 | + , DerKeyType |
| 14 | + , pkcs1 |
| 15 | + , spki |
| 16 | + , newSecretKey |
| 17 | + , newPublicKeyBuf |
| 18 | + , newPublicKeyObj |
| 19 | + , NewPublicKeyOptions |
| 20 | + , newPrivateKeyBuf |
| 21 | + , newPrivateKeyObj |
| 22 | + , NewPrivateKeyOptions |
| 23 | + , assymetricKeyDetails |
| 24 | + , assymetricKeyType |
| 25 | + , symmetricKeySize |
| 26 | + , type' |
| 27 | + , keyType |
| 28 | + ) where |
| 29 | + |
| 30 | +import Prelude |
| 31 | + |
| 32 | +import Data.Function.Uncurried (Fn2, runFn2) |
| 33 | +import Effect (Effect) |
| 34 | +import Effect.Uncurried (EffectFn1, runEffectFn1) |
| 35 | +import Foreign (Foreign) |
| 36 | +import Node.Buffer (Buffer) |
| 37 | +import Partial.Unsafe (unsafeCrashWith) |
| 38 | +import Prim.Row as Row |
| 39 | +import Unsafe.Coerce (unsafeCoerce) |
| 40 | + |
| 41 | +data KeyObjectType |
| 42 | + |
| 43 | +foreign import data Symmetric :: KeyObjectType |
| 44 | +foreign import data Asymmetric :: AsymmetricKeyType -> KeyObjectType |
| 45 | + |
| 46 | +data AsymmetricKeyType |
| 47 | + |
| 48 | +foreign import data Private :: AsymmetricKeyType |
| 49 | +foreign import data Public :: AsymmetricKeyType |
| 50 | + |
| 51 | +-- | Node.js uses a `KeyObject` class to represent a symmetric or asymmetric key, and each kind of key exposes different functions. |
| 52 | +-- | |
| 53 | +-- | Most applications should consider using the new `KeyObject` API instead of passing keys as strings or Buffers |
| 54 | +-- | due to improved security features. |
| 55 | +-- | |
| 56 | +-- | `KeyObject` instances can be passed to other threads via `postMessage()`. |
| 57 | +-- | The receiver obtains a cloned `KeyObject`, and the `KeyObject` does not need to be listed in the `transferList` argument. |
| 58 | +foreign import data KeyObject :: KeyObjectType -> Type |
| 59 | + |
| 60 | +instance Eq (KeyObject a) where |
| 61 | + eq a b = runFn2 eqKeyObjectImpl a b |
| 62 | + |
| 63 | +foreign import eqKeyObjectImpl :: forall a. Fn2 (KeyObject a) (KeyObject a) Boolean |
| 64 | + |
| 65 | +newtype KeyFormat = KeyFormat String |
| 66 | + |
| 67 | +derive newtype instance Eq KeyFormat |
| 68 | +derive newtype instance Ord KeyFormat |
| 69 | +derive newtype instance Show KeyFormat |
| 70 | + |
| 71 | +pem = KeyFormat "pem" :: KeyFormat |
| 72 | +der = KeyFormat "der" :: KeyFormat |
| 73 | +jwk = KeyFormat "jwk" :: KeyFormat |
| 74 | + |
| 75 | +newtype DerKeyType = DerKeyType String |
| 76 | + |
| 77 | +derive newtype instance Eq DerKeyType |
| 78 | +derive newtype instance Ord DerKeyType |
| 79 | +derive newtype instance Show DerKeyType |
| 80 | + |
| 81 | +pkcs1 = DerKeyType "pkcs1" :: DerKeyType |
| 82 | +spki = DerKeyType "spki" :: DerKeyType |
| 83 | + |
| 84 | +foreign import newSecretKeyImpl :: EffectFn1 (Buffer) ((KeyObject Symmetric)) |
| 85 | + |
| 86 | +-- | Creates and returns a new key object containing a secret key for symmetric encryption or Hmac. |
| 87 | +newSecretKey :: Buffer -> Effect (KeyObject Symmetric) |
| 88 | +newSecretKey key = runEffectFn1 newSecretKeyImpl key |
| 89 | + |
| 90 | +foreign import newPublicKeyBufImpl :: EffectFn1 (Buffer) (KeyObject (Asymmetric Public)) |
| 91 | + |
| 92 | +-- | Creates and returns a new key object containing a public key. Format is assumed to be 'pem'; |
| 93 | +newPublicKeyBuf :: Buffer -> Effect (KeyObject (Asymmetric Public)) |
| 94 | +newPublicKeyBuf buffer = runEffectFn1 newPublicKeyBufImpl buffer |
| 95 | + |
| 96 | +foreign import newPublicKeyObjImpl :: forall r. EffectFn1 ({ | r }) ((KeyObject (Asymmetric Public))) |
| 97 | + |
| 98 | +-- | Creates and returns a new key object containing a public key. |
| 99 | +newPublicKeyObj :: forall r trash. Row.Union r trash NewPublicKeyOptions => { | r } -> Effect (KeyObject (Asymmetric Public)) |
| 100 | +newPublicKeyObj r = runEffectFn1 newPublicKeyObjImpl r |
| 101 | + |
| 102 | +type NewPublicKeyOptions = |
| 103 | + ( key :: Buffer |
| 104 | + , format :: KeyFormat |
| 105 | + , type :: DerKeyType |
| 106 | + ) |
| 107 | + |
| 108 | +foreign import newPrivateKeyBufImpl :: EffectFn1 (Buffer) ((KeyObject (Asymmetric Private))) |
| 109 | + |
| 110 | +-- | Creates and returns a new key object containing a private key. Format is assumed to be 'pem'; |
| 111 | +newPrivateKeyBuf :: Buffer -> Effect (KeyObject (Asymmetric Private)) |
| 112 | +newPrivateKeyBuf buffer = runEffectFn1 newPrivateKeyBufImpl buffer |
| 113 | + |
| 114 | +foreign import newPrivateKeyObjImpl :: forall r. EffectFn1 ({ | r }) ((KeyObject (Asymmetric Private))) |
| 115 | + |
| 116 | +-- | Creates and returns a new key object containing a private key. |
| 117 | +-- | If the private key is encrypted, a passphrase must be specified. The length of the passphrase is limited to 1024 bytes. |
| 118 | +newPrivateKeyObj :: forall r trash. Row.Union r trash NewPrivateKeyOptions => { | r } -> Effect (KeyObject (Asymmetric Private)) |
| 119 | +newPrivateKeyObj r = runEffectFn1 newPrivateKeyObjImpl r |
| 120 | + |
| 121 | +type NewPrivateKeyOptions = |
| 122 | + ( key :: Buffer |
| 123 | + , format :: KeyFormat |
| 124 | + , type :: DerKeyType |
| 125 | + , passphrase :: Buffer |
| 126 | + ) |
| 127 | + |
| 128 | + |
| 129 | +-- | Returns an object whose fields depend on the algorithm of the `KeyObject` |
| 130 | +-- | - `modulusLength`: `number` Key size in bits (RSA, DSA). |
| 131 | +-- | - `publicExponent`: `bigint` Public exponent (RSA). |
| 132 | +-- | - `hashAlgorithm`: `string` Name of the message digest (RSA-PSS). |
| 133 | +-- | - `mgf1HashAlgorithm`: `string` Name of the message digest used by MGF1 (RSA-PSS). |
| 134 | +-- | - `saltLength`: `number` Minimal salt length in bytes (RSA-PSS). |
| 135 | +-- | - `divisorLength`: `number` Size of q in bits (DSA). |
| 136 | +-- | - `namedCurve`: `string` Name of the curve (EC). |
| 137 | +-- | |
| 138 | +-- | This property exists only on asymmetric keys. Depending on the type of the key, this object contains information about the key. None of the information obtained through this property can be used to uniquely identify a key or to compromise the security of the key. |
| 139 | +-- | |
| 140 | +-- | For RSA-PSS keys, if the key material contains a RSASSA-PSS-params sequence, the hashAlgorithm, mgf1HashAlgorithm, and saltLength properties will be set. |
| 141 | +-- | |
| 142 | +-- | Other key details might be exposed via this API using additional attributes. |
| 143 | +foreign import assymetricKeyDetails :: forall x. KeyObject (Asymmetric x) -> Foreign |
| 144 | + |
| 145 | +-- | For asymmetric keys, this property represents the type of the key. Supported key types are: |
| 146 | +-- | - 'rsa' (OID 1.2.840.113549.1.1.1) |
| 147 | +-- | - 'rsa-pss' (OID 1.2.840.113549.1.1.10) |
| 148 | +-- | - 'dsa' (OID 1.2.840.10040.4.1) |
| 149 | +-- | - 'ec' (OID 1.2.840.10045.2.1) |
| 150 | +-- | - 'x25519' (OID 1.3.101.110) |
| 151 | +-- | - 'x448' (OID 1.3.101.111) |
| 152 | +-- | - 'ed25519' (OID 1.3.101.112) |
| 153 | +-- | - 'ed448' (OID 1.3.101.113) |
| 154 | +-- | - 'dh' (OID 1.2.840.113549.1.3.1) |
| 155 | +-- | This property is undefined for unrecognized KeyObject types and symmetric keys. |
| 156 | +foreign import assymetricKeyType :: forall x. KeyObject (Asymmetric x) -> String |
| 157 | + |
| 158 | +-- | For secret keys, this property represents the size of the key in bytes. This property is undefined for asymmetric keys. |
| 159 | +foreign import symmetricKeySize :: KeyObject Symmetric -> Number |
| 160 | + |
| 161 | +foreign import typeImpl :: forall a. KeyObject a -> String |
| 162 | + |
| 163 | +-- | Depending on the type of this KeyObject, this property is either 'secret' for secret (symmetric) keys, |
| 164 | +-- | 'public' for public (asymmetric) keys or 'private' for private (asymmetric) keys. |
| 165 | +type' :: forall a. KeyObject a -> String |
| 166 | +type' ko = typeImpl ko |
| 167 | + |
| 168 | +-- | Eliminator for a KeyObject when one doesn't know what the `type` is. |
| 169 | +keyType |
| 170 | + :: forall x a |
| 171 | + . KeyObject x |
| 172 | + -> (KeyObject Symmetric -> a) |
| 173 | + -> (KeyObject (Asymmetric Public) -> a) |
| 174 | + -> (KeyObject (Asymmetric Private) -> a) |
| 175 | + -> a |
| 176 | +keyType ko onSym onPub onPriv = case type' ko of |
| 177 | + "secret" -> onSym $ (unsafeCoerce :: _ -> KeyObject Symmetric) ko |
| 178 | + "public" -> onPub $ (unsafeCoerce :: _ -> KeyObject (Asymmetric Public)) ko |
| 179 | + "private" -> onPriv $ (unsafeCoerce :: _ -> KeyObject (Asymmetric Private)) ko |
| 180 | + ty -> unsafeCrashWith $ "Impossible key type: " <> ty |
0 commit comments