From 6af3cb6406bd97ff421207d18fe2b8b05e1b96f4 Mon Sep 17 00:00:00 2001 From: Eugene Kabanov Date: Tue, 21 Jul 2020 23:10:21 +0300 Subject: [PATCH] Public key infrastructure filters. (#272) * Initial commit. * Workaround nim's bug and add some other compilation error fixes. * Rename to libp2p_pki_schemes. Fix secio. Add tests. * Attempt to fix command line. * Fix command line. Show status in tests. --- libp2p.nimble | 15 +- libp2p/crypto/crypto.nim | 700 ++++++++++++++++++++---------- libp2p/protocols/secure/secio.nim | 13 +- libp2p/standard_setup.nim | 2 +- tests/testpkifilter.nim | 239 ++++++++++ 5 files changed, 723 insertions(+), 246 deletions(-) create mode 100644 tests/testpkifilter.nim diff --git a/libp2p.nimble b/libp2p.nimble index 106cd59d5..ef37b2dca 100644 --- a/libp2p.nimble +++ b/libp2p.nimble @@ -16,11 +16,13 @@ requires "nim >= 1.2.0", "secp256k1", "stew >= 0.1.0" -proc runTest(filename: string, verify: bool = true, sign: bool = true) = +proc runTest(filename: string, verify: bool = true, sign: bool = true, + moreoptions: string = "") = var excstr = "nim c --opt:speed -d:debug --verbosity:0 --hints:off" excstr.add(" --warning[CaseTransition]:off --warning[ObservableStores]:off --warning[LockLevel]:off") excstr.add(" -d:libp2p_pubsub_sign=" & $sign) excstr.add(" -d:libp2p_pubsub_verify=" & $verify) + excstr.add(" " & moreoptions & " ") if verify and sign: # build it with TRACE and JSON logs exec excstr & " -d:chronicles_log_level=TRACE -d:chronicles_sinks:json" & " tests/" & filename @@ -48,11 +50,22 @@ task testpubsub, "Runs pubsub tests": runTest("pubsub/testpubsub") runTest("pubsub/testpubsub", sign = false, verify = false) +task testfilter, "Run PKI filter test": + runTest("testpkifilter", + moreoptions = "-d:libp2p_pki_schemes=\"secp256k1\"") + runTest("testpkifilter", + moreoptions = "-d:libp2p_pki_schemes=\"secp256k1;ed25519\"") + runTest("testpkifilter", + moreoptions = "-d:libp2p_pki_schemes=\"secp256k1;ed25519;ecnist\"") + runTest("testpkifilter", + moreoptions = "-d:libp2p_pki_schemes=") + task test, "Runs the test suite": exec "nimble testnative" exec "nimble testpubsub" exec "nimble testdaemon" exec "nimble testinterop" + exec "nimble testfilter" task examples_build, "Build the samples": buildSample("directchat") diff --git a/libp2p/crypto/crypto.nim b/libp2p/crypto/crypto.nim index a6a291e4e..820bde77d 100644 --- a/libp2p/crypto/crypto.nim +++ b/libp2p/crypto/crypto.nim @@ -8,29 +8,79 @@ ## those terms. ## This module implements Public Key and Private Key interface for libp2p. - {.push raises: [Defect].} +from strutils import split, strip, cmpIgnoreCase -import rsa, ecnist, ed25519/ed25519, secp, bearssl -import ../protobuf/minprotobuf, ../vbuffer, ../multihash, ../multicodec -import nimcrypto/[rijndael, blowfish, twofish, sha2, hash, hmac, utils] -import ../utility -import stew/results -export results - -# This is workaround for Nim's `import` bug -export rijndael, blowfish, twofish, sha2, hash, hmac, utils - -from strutils import split +const libp2p_pki_schemes* {.strdefine.} = "rsa,ed25519,secp256k1,ecnist" type PKScheme* = enum RSA = 0, Ed25519, Secp256k1, - ECDSA, - NoSupport + ECDSA +proc initSupportedSchemes(list: static string): set[PKScheme] = + var res: set[PKScheme] + + let schemes = split(list, {',', ';', '|'}) + for item in schemes: + if cmpIgnoreCase(strip(item), "rsa") == 0: + res.incl(PKScheme.RSA) + elif cmpIgnoreCase(strip(item), "ed25519") == 0: + res.incl(PKScheme.Ed25519) + elif cmpIgnoreCase(strip(item), "secp256k1") == 0: + res.incl(PKScheme.Secp256k1) + elif cmpIgnoreCase(strip(item), "ecnist") == 0: + res.incl(PKScheme.ECDSA) + if len(res) == 0: + res = {PKScheme.RSA, PKScheme.Ed25519, PKScheme.Secp256k1, PKScheme.ECDSA} + res + +proc initSupportedSchemes(schemes: static set[PKScheme]): set[int8] = + var res: set[int8] + if PKScheme.RSA in schemes: + res.incl(int8(PKScheme.RSA)) + if PKScheme.Ed25519 in schemes: + res.incl(int8(PKScheme.Ed25519)) + if PKScheme.Secp256k1 in schemes: + res.incl(int8(PKScheme.Secp256k1)) + if PKScheme.ECDSA in schemes: + res.incl(int8(PKScheme.ECDSA)) + res + +const + SupportedSchemes* = initSupportedSchemes(libp2p_pki_schemes) + SupportedSchemesInt* = initSupportedSchemes(SupportedSchemes) + RsaDefaultKeySize* = 3072 + +template supported*(scheme: PKScheme): bool = + ## Returns true if specified ``scheme`` is currently available. + scheme in SupportedSchemes + +when supported(PKScheme.RSA): + import rsa +when supported(PKScheme.Ed25519): + import ed25519/ed25519 +when supported(PKScheme.Secp256k1): + import secp + +# We are still importing `ecnist` because, it is used for SECIO handshake, +# but it will be impossible to create ECNIST keys or import ECNIST keys. + +import ecnist, bearssl +import ../protobuf/minprotobuf, ../vbuffer, ../multihash, ../multicodec +import nimcrypto/[rijndael, twofish, sha2, hash, hmac, utils] +import ../utility +import stew/results +export results + +# This is workaround for Nim's `import` bug +export rijndael, twofish, sha2, hash, hmac, utils + +from strutils import split + +type DigestSheme* = enum Sha256, Sha512 @@ -39,29 +89,49 @@ type PublicKey* = object case scheme*: PKScheme - of RSA: - rsakey*: rsa.RsaPublicKey - of Ed25519: - edkey*: EdPublicKey - of Secp256k1: - skkey*: SkPublicKey - of ECDSA: - eckey*: ecnist.EcPublicKey - of NoSupport: - discard + of PKScheme.RSA: + when PKScheme.RSA in SupportedSchemes: + rsakey*: rsa.RsaPublicKey + else: + discard + of PKScheme.Ed25519: + when supported(PKScheme.Ed25519): + edkey*: EdPublicKey + else: + discard + of PKScheme.Secp256k1: + when supported(PKScheme.Secp256k1): + skkey*: SkPublicKey + else: + discard + of PKScheme.ECDSA: + when supported(PKScheme.ECDSA): + eckey*: ecnist.EcPublicKey + else: + discard PrivateKey* = object case scheme*: PKScheme - of RSA: - rsakey*: rsa.RsaPrivateKey - of Ed25519: - edkey*: EdPrivateKey - of Secp256k1: - skkey*: SkPrivateKey - of ECDSA: - eckey*: ecnist.EcPrivateKey - of NoSupport: - discard + of PKScheme.RSA: + when supported(PKScheme.RSA): + rsakey*: rsa.RsaPrivateKey + else: + discard + of PKScheme.Ed25519: + when supported(PKScheme.Ed25519): + edkey*: EdPrivateKey + else: + discard + of PKScheme.Secp256k1: + when supported(PKScheme.Secp256k1): + skkey*: SkPrivateKey + else: + discard + of PKSCheme.ECDSA: + when supported(PKSCheme.ECDSA): + eckey*: ecnist.EcPrivateKey + else: + discard KeyPair* = object seckey*: PrivateKey @@ -84,11 +154,6 @@ type CryptoResult*[T] = Result[T, CryptoError] -const - SupportedSchemes* = {RSA, Ed25519, Secp256k1, ECDSA} - SupportedSchemesInt* = {int8(RSA), int8(Ed25519), int8(Secp256k1), - int8(ECDSA)} - template orError*(exp: untyped, err: untyped): untyped = (exp.mapErr do (_: auto) -> auto: err) @@ -106,77 +171,162 @@ proc newRng*(): ref BrHmacDrbgContext = return nil rng -proc random*( - T: typedesc[PrivateKey], scheme: PKScheme, - rng: var BrHmacDrbgContext, bits = DefaultKeySize): CryptoResult[PrivateKey] = +proc random*(T: typedesc[PrivateKey], scheme: PKScheme, + rng: var BrHmacDrbgContext, + bits = RsaDefaultKeySize): CryptoResult[PrivateKey] = ## Generate random private key for scheme ``scheme``. ## ## ``bits`` is number of bits for RSA key, ``bits`` value must be in - ## [512, 4096], default value is 2048 bits. + ## [2048, 4096], default value is 3072 bits. case scheme - of RSA: - let rsakey = ? RsaPrivateKey.random(rng, bits).orError(KeyError) - ok(PrivateKey(scheme: scheme, rsakey: rsakey)) - of Ed25519: + of PKScheme.RSA: + when supported(PKScheme.RSA): + let rsakey = ? RsaPrivateKey.random(rng, bits).orError(KeyError) + ok(PrivateKey(scheme: scheme, rsakey: rsakey)) + else: + err(SchemeError) + of PKScheme.Ed25519: + when supported(PKScheme.Ed25519): + let edkey = EdPrivateKey.random(rng) + ok(PrivateKey(scheme: scheme, edkey: edkey)) + else: + err(SchemeError) + of PKScheme.ECDSA: + when supported(PKScheme.ECDSA): + let eckey = ? ecnist.EcPrivateKey.random(Secp256r1, rng).orError(KeyError) + ok(PrivateKey(scheme: scheme, eckey: eckey)) + else: + err(SchemeError) + of PKScheme.Secp256k1: + when supported(PKScheme.Secp256k1): + let skkey = SkPrivateKey.random(rng) + ok(PrivateKey(scheme: scheme, skkey: skkey)) + else: + err(SchemeError) + +proc random*(T: typedesc[PrivateKey], rng: var BrHmacDrbgContext, + bits = RsaDefaultKeySize): CryptoResult[PrivateKey] = + ## Generate random private key using default public-key cryptography scheme. + ## + ## Default public-key cryptography schemes are following order: + ## ed25519, secp256k1, RSA, secp256r1. + ## + ## So will be used first available (supported) method. + when supported(PKScheme.Ed25519): let edkey = EdPrivateKey.random(rng) - ok(PrivateKey(scheme: scheme, edkey: edkey)) - of ECDSA: - let eckey = ? ecnist.EcPrivateKey.random(Secp256r1, rng).orError(KeyError) - ok(PrivateKey(scheme: scheme, eckey: eckey)) - of Secp256k1: + ok(PrivateKey(scheme: PKScheme.Ed25519, edkey: edkey)) + elif supported(PKScheme.Secp256k1): let skkey = SkPrivateKey.random(rng) - ok(PrivateKey(scheme: scheme, skkey: skkey)) + ok(PrivateKey(scheme: PKScheme.Secp256k1, skkey: skkey)) + elif supported(PKScheme.RSA): + let rsakey = ? RsaPrivateKey.random(rng, bits).orError(KeyError) + ok(PrivateKey(scheme: PKScheme.RSA, rsakey: rsakey)) + elif supported(PKScheme.ECDSA): + let eckey = ? ecnist.EcPrivateKey.random(Secp256r1, rng).orError(KeyError) + ok(PrivateKey(scheme: PKScheme.ECDSA, eckey: eckey)) else: err(SchemeError) -proc random*( - T: typedesc[KeyPair], scheme: PKScheme, - rng: var BrHmacDrbgContext, bits = DefaultKeySize): CryptoResult[KeyPair] = +proc random*(T: typedesc[KeyPair], scheme: PKScheme, + rng: var BrHmacDrbgContext, + bits = RsaDefaultKeySize): CryptoResult[KeyPair] = ## Generate random key pair for scheme ``scheme``. ## ## ``bits`` is number of bits for RSA key, ``bits`` value must be in ## [512, 4096], default value is 2048 bits. case scheme - of RSA: - let pair = ? RsaKeyPair.random(rng, bits).orError(KeyError) - ok(KeyPair( - seckey: PrivateKey(scheme: scheme, rsakey: pair.seckey), - pubkey: PublicKey(scheme: scheme, rsakey: pair.pubkey))) - of Ed25519: + of PKScheme.RSA: + when supported(PKScheme.RSA): + let pair = ? RsaKeyPair.random(rng, bits).orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, rsakey: pair.seckey), + pubkey: PublicKey(scheme: scheme, rsakey: pair.pubkey))) + else: + err(SchemeError) + of PKScheme.Ed25519: + when supported(PKScheme.Ed25519): + let pair = EdKeyPair.random(rng) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, edkey: pair.seckey), + pubkey: PublicKey(scheme: scheme, edkey: pair.pubkey))) + else: + err(SchemeError) + of PKScheme.ECDSA: + when supported(PKScheme.ECDSA): + let pair = ? EcKeyPair.random(Secp256r1, rng).orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, eckey: pair.seckey), + pubkey: PublicKey(scheme: scheme, eckey: pair.pubkey))) + else: + err(SchemeError) + of PKScheme.Secp256k1: + when supported(PKScheme.Secp256k1): + let pair = SkKeyPair.random(rng) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, skkey: pair.seckey), + pubkey: PublicKey(scheme: scheme, skkey: pair.pubkey))) + else: + err(SchemeError) + +proc random*(T: typedesc[KeyPair], rng: var BrHmacDrbgContext, + bits = RsaDefaultKeySize): CryptoResult[KeyPair] = + ## Generate random private pair of keys using default public-key cryptography + ## scheme. + ## + ## Default public-key cryptography schemes are following order: + ## ed25519, secp256k1, RSA, secp256r1. + ## + ## So will be used first available (supported) method. + when supported(PKScheme.Ed25519): let pair = EdKeyPair.random(rng) ok(KeyPair( - seckey: PrivateKey(scheme: scheme, edkey: pair.seckey), - pubkey: PublicKey(scheme: scheme, edkey: pair.pubkey))) - of ECDSA: - let pair = ? EcKeyPair.random(Secp256r1, rng).orError(KeyError) - ok(KeyPair( - seckey: PrivateKey(scheme: scheme, eckey: pair.seckey), - pubkey: PublicKey(scheme: scheme, eckey: pair.pubkey))) - of Secp256k1: + seckey: PrivateKey(scheme: PKScheme.Ed25519, edkey: pair.seckey), + pubkey: PublicKey(scheme: PKScheme.Ed25519, edkey: pair.pubkey))) + elif supported(PKScheme.Secp256k1): let pair = SkKeyPair.random(rng) ok(KeyPair( - seckey: PrivateKey(scheme: scheme, skkey: pair.seckey), - pubkey: PublicKey(scheme: scheme, skkey: pair.pubkey))) + seckey: PrivateKey(scheme: PKScheme.Secp256k1, skkey: pair.seckey), + pubkey: PublicKey(scheme: PKScheme.Secp256k1, skkey: pair.pubkey))) + elif supported(PKScheme.RSA): + let pair = ? RsaKeyPair.random(rng, bits).orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: PKScheme.RSA, rsakey: pair.seckey), + pubkey: PublicKey(scheme: PKScheme.RSA, rsakey: pair.pubkey))) + elif supported(PKScheme.ECDSA): + let pair = ? EcKeyPair.random(Secp256r1, rng).orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: PKScheme.ECDSA, eckey: pair.seckey), + pubkey: PublicKey(scheme: PKScheme.ECDSA, eckey: pair.pubkey))) else: err(SchemeError) proc getKey*(key: PrivateKey): CryptoResult[PublicKey] = ## Get public key from corresponding private key ``key``. case key.scheme - of RSA: - let rsakey = key.rsakey.getKey() - ok(PublicKey(scheme: RSA, rsakey: rsakey)) - of Ed25519: - let edkey = key.edkey.getKey() - ok(PublicKey(scheme: Ed25519, edkey: edkey)) - of ECDSA: - let eckey = ? key.eckey.getKey().orError(KeyError) - ok(PublicKey(scheme: ECDSA, eckey: eckey)) - of Secp256k1: - let skkey = key.skkey.getKey() - ok(PublicKey(scheme: Secp256k1, skkey: skkey)) - else: - err(KeyError) + of PKScheme.RSA: + when supported(PKScheme.RSA): + let rsakey = key.rsakey.getKey() + ok(PublicKey(scheme: RSA, rsakey: rsakey)) + else: + err(SchemeError) + of PKScheme.Ed25519: + when supported(PKScheme.Ed25519): + let edkey = key.edkey.getKey() + ok(PublicKey(scheme: Ed25519, edkey: edkey)) + else: + err(SchemeError) + of PKScheme.ECDSA: + when supported(PKScheme.ECDSA): + let eckey = ? key.eckey.getKey().orError(KeyError) + ok(PublicKey(scheme: ECDSA, eckey: eckey)) + else: + err(SchemeError) + of PKScheme.Secp256k1: + when supported(PKScheme.Secp256k1): + let skkey = key.skkey.getKey() + ok(PublicKey(scheme: Secp256k1, skkey: skkey)) + else: + err(SchemeError) proc toRawBytes*(key: PrivateKey | PublicKey, data: var openarray[byte]): CryptoResult[int] = @@ -185,31 +335,51 @@ proc toRawBytes*(key: PrivateKey | PublicKey, ## ## Returns number of bytes (octets) needed to store private key ``key``. case key.scheme - of RSA: - key.rsakey.toBytes(data).orError(KeyError) - of Ed25519: - ok(key.edkey.toBytes(data)) - of ECDSA: - key.eckey.toBytes(data).orError(KeyError) - of Secp256k1: - key.skkey.toBytes(data).orError(KeyError) - else: - err(KeyError) + of PKScheme.RSA: + when supported(PKScheme.RSA): + key.rsakey.toBytes(data).orError(KeyError) + else: + err(SchemeError) + of PKScheme.Ed25519: + when supported(PKScheme.Ed25519): + ok(key.edkey.toBytes(data)) + else: + err(SchemeError) + of PKScheme.ECDSA: + when supported(PKScheme.ECDSA): + key.eckey.toBytes(data).orError(KeyError) + else: + err(SchemeError) + of PKScheme.Secp256k1: + when supported(PKScheme.Secp256k1): + key.skkey.toBytes(data).orError(KeyError) + else: + err(SchemeError) proc getRawBytes*(key: PrivateKey | PublicKey): CryptoResult[seq[byte]] = ## Return private key ``key`` in binary form (using scheme's own ## serialization). case key.scheme - of RSA: - key.rsakey.getBytes().orError(KeyError) - of Ed25519: - ok(key.edkey.getBytes()) - of ECDSA: - key.eckey.getBytes().orError(KeyError) - of Secp256k1: - ok(key.skkey.getBytes()) - else: - err(KeyError) + of PKScheme.RSA: + when supported(PKScheme.RSA): + key.rsakey.getBytes().orError(KeyError) + else: + err(SchemeError) + of PKScheme.Ed25519: + when supported(PKScheme.Ed25519): + ok(key.edkey.getBytes()) + else: + err(SchemeError) + of PKScheme.ECDSA: + when supported(PKScheme.ECDSA): + key.eckey.getBytes().orError(KeyError) + else: + err(SchemeError) + of PKScheme.Secp256k1: + when supported(PKScheme.Secp256k1): + ok(key.skkey.getBytes()) + else: + err(SchemeError) proc toBytes*(key: PrivateKey, data: var openarray[byte]): CryptoResult[int] = ## Serialize private key ``key`` (using libp2p protobuf scheme) and store @@ -276,12 +446,18 @@ proc init*[T: PrivateKey|PublicKey](key: var T, data: openarray[byte]): bool = ## Returns ``true`` on success. var id: uint64 var buffer: seq[byte] - if len(data) > 0: + if len(data) <= 0: + false + else: var pb = initProtoBuffer(@data) let r1 = pb.getField(1, id) let r2 = pb.getField(2, buffer) - if r1.isOk() and r1.get() and r2.isOk() and r2.get(): - if cast[int8](id) in SupportedSchemesInt and len(buffer) > 0: + if not(r1.isOk() and r1.get() and r2.isOk() and r2.get()): + false + else: + if cast[int8](id) notin SupportedSchemesInt or len(buffer) <= 0: + false + else: var scheme = cast[PKScheme](cast[int8](id)) when key is PrivateKey: var nkey = PrivateKey(scheme: scheme) @@ -289,23 +465,41 @@ proc init*[T: PrivateKey|PublicKey](key: var T, data: openarray[byte]): bool = var nkey = PublicKey(scheme: scheme) case scheme: of PKScheme.RSA: - if init(nkey.rsakey, buffer).isOk: - key = nkey - return true + when supported(PKScheme.RSA): + if init(nkey.rsakey, buffer).isOk: + key = nkey + true + else: + false + else: + false of PKScheme.Ed25519: - if init(nkey.edkey, buffer): - key = nkey - return true + when supported(PKScheme.Ed25519): + if init(nkey.edkey, buffer): + key = nkey + true + else: + false + else: + false of PKScheme.ECDSA: - if init(nkey.eckey, buffer).isOk: - key = nkey - return true + when supported(PKScheme.ECDSA): + if init(nkey.eckey, buffer).isOk: + key = nkey + true + else: + false + else: + false of PKScheme.Secp256k1: - if init(nkey.skkey, buffer).isOk: - key = nkey - return true - else: - return false + when supported(PKScheme.Secp256k1): + if init(nkey.skkey, buffer).isOk: + key = nkey + true + else: + false + else: + false proc init*(sig: var Signature, data: openarray[byte]): bool = ## Initialize signature ``sig`` from raw binary form. @@ -321,7 +515,7 @@ proc init*[T: PrivateKey|PublicKey](key: var T, data: string): bool = ## ## Returns ``true`` on success. try: - key.init(fromHex(data)) + key.init(utils.fromHex(data)) except ValueError: false @@ -331,7 +525,7 @@ proc init*(sig: var Signature, data: string): bool = ## ## Returns ``true`` on success. try: - sig.init(fromHex(data)) + sig.init(utils.fromHex(data)) except ValueError: false @@ -366,40 +560,46 @@ proc init*(t: typedesc[PrivateKey], data: string): CryptoResult[PrivateKey] = ## Create new private key from libp2p's protobuf serialized hexadecimal string ## form. try: - t.init(fromHex(data)) + t.init(utils.fromHex(data)) except ValueError: err(KeyError) -proc init*(t: typedesc[PrivateKey], key: rsa.RsaPrivateKey): PrivateKey = - PrivateKey(scheme: RSA, rsakey: key) -proc init*(t: typedesc[PrivateKey], key: EdPrivateKey): PrivateKey = - PrivateKey(scheme: Ed25519, edkey: key) -proc init*(t: typedesc[PrivateKey], key: SkPrivateKey): PrivateKey = - PrivateKey(scheme: Secp256k1, skkey: key) -proc init*(t: typedesc[PrivateKey], key: ecnist.EcPrivateKey): PrivateKey = - PrivateKey(scheme: ECDSA, eckey: key) +when supported(PKScheme.RSA): + proc init*(t: typedesc[PrivateKey], key: rsa.RsaPrivateKey): PrivateKey = + PrivateKey(scheme: RSA, rsakey: key) + proc init*(t: typedesc[PublicKey], key: rsa.RsaPublicKey): PublicKey = + PublicKey(scheme: RSA, rsakey: key) -proc init*(t: typedesc[PublicKey], key: rsa.RsaPublicKey): PublicKey = - PublicKey(scheme: RSA, rsakey: key) -proc init*(t: typedesc[PublicKey], key: EdPublicKey): PublicKey = - PublicKey(scheme: Ed25519, edkey: key) -proc init*(t: typedesc[PublicKey], key: SkPublicKey): PublicKey = - PublicKey(scheme: Secp256k1, skkey: key) -proc init*(t: typedesc[PublicKey], key: ecnist.EcPublicKey): PublicKey = - PublicKey(scheme: ECDSA, eckey: key) +when supported(PKScheme.Ed25519): + proc init*(t: typedesc[PrivateKey], key: EdPrivateKey): PrivateKey = + PrivateKey(scheme: Ed25519, edkey: key) + proc init*(t: typedesc[PublicKey], key: EdPublicKey): PublicKey = + PublicKey(scheme: Ed25519, edkey: key) + +when supported(PKScheme.Secp256k1): + proc init*(t: typedesc[PrivateKey], key: SkPrivateKey): PrivateKey = + PrivateKey(scheme: Secp256k1, skkey: key) + proc init*(t: typedesc[PublicKey], key: SkPublicKey): PublicKey = + PublicKey(scheme: Secp256k1, skkey: key) + +when supported(PKScheme.ECDSA): + proc init*(t: typedesc[PrivateKey], key: ecnist.EcPrivateKey): PrivateKey = + PrivateKey(scheme: ECDSA, eckey: key) + proc init*(t: typedesc[PublicKey], key: ecnist.EcPublicKey): PublicKey = + PublicKey(scheme: ECDSA, eckey: key) proc init*(t: typedesc[PublicKey], data: string): CryptoResult[PublicKey] = ## Create new public key from libp2p's protobuf serialized hexadecimal string ## form. try: - t.init(fromHex(data)) + t.init(utils.fromHex(data)) except ValueError: err(KeyError) proc init*(t: typedesc[Signature], data: string): CryptoResult[Signature] = ## Create new signature from serialized hexadecimal string form. try: - t.init(fromHex(data)) + t.init(utils.fromHex(data)) except ValueError: err(SigError) @@ -409,15 +609,25 @@ proc `==`*(key1, key2: PublicKey): bool {.inline.} = if key1.scheme == key2.scheme: case key1.scheme of PKScheme.RSA: - (key1.rsakey == key2.rsakey) + when supported(PKScheme.RSA): + (key1.rsakey == key2.rsakey) + else: + false of PKScheme.Ed25519: - (key1.edkey == key2.edkey) + when supported(PKScheme.Ed25519): + (key1.edkey == key2.edkey) + else: + false of PKScheme.ECDSA: - (key1.eckey == key2.eckey) + when supported(PKScheme.ECDSA): + (key1.eckey == key2.eckey) + else: + false of PKScheme.Secp256k1: - (key1.skkey == key2.skkey) - of PKScheme.NoSupport: - false + when supported(PKScheme.Secp256k1): + (key1.skkey == key2.skkey) + else: + false else: false @@ -427,15 +637,25 @@ proc `==`*(key1, key2: PrivateKey): bool = if key1.scheme == key2.scheme: case key1.scheme of PKScheme.RSA: - (key1.rsakey == key2.rsakey) + when supported(PKScheme.RSA): + (key1.rsakey == key2.rsakey) + else: + false of PKScheme.Ed25519: - (key1.edkey == key2.edkey) + when supported(PKScheme.Ed25519): + (key1.edkey == key2.edkey) + else: + false of PKScheme.ECDSA: - (key1.eckey == key2.eckey) + when supported(PKScheme.ECDSA): + (key1.eckey == key2.eckey) + else: + false of PKScheme.Secp256k1: - (key1.skkey == key2.skkey) - of PKScheme.NoSupport: - false + when supported(PKScheme.Secp256k1): + (key1.skkey == key2.skkey) + else: + false else: false @@ -443,29 +663,49 @@ proc `$`*(key: PrivateKey|PublicKey): string = ## Get string representation of private/public key ``key``. case key.scheme: of PKScheme.RSA: - $(key.rsakey) + when supported(PKScheme.RSA): + $(key.rsakey) + else: + "unsupported RSA key" of PKScheme.Ed25519: - "ed25519 key (" & $key.edkey & ")" + when supported(PKScheme.Ed25519): + "ed25519 key (" & $key.edkey & ")" + else: + "unsupported ed25519 key" of PKScheme.ECDSA: - "secp256r1 key (" & $key.eckey & ")" + when supported(PKScheme.ECDSA): + "secp256r1 key (" & $key.eckey & ")" + else: + "unsupported secp256r1 key" of PKScheme.Secp256k1: - "secp256k1 key (" & $key.skkey & ")" - of PKScheme.NoSupport: - "not supported" + when supported(PKScheme.Secp256k1): + "secp256k1 key (" & $key.skkey & ")" + else: + "unsupported secp256k1 key" func shortLog*(key: PrivateKey|PublicKey): string = ## Get short string representation of private/public key ``key``. case key.scheme: of PKScheme.RSA: - ($key.rsakey).shortLog + when supported(PKScheme.RSA): + ($key.rsakey).shortLog + else: + "unsupported RSA key" of PKScheme.Ed25519: - "ed25519 key (" & ($key.edkey).shortLog & ")" + when supported(PKScheme.Ed25519): + "ed25519 key (" & ($key.edkey).shortLog & ")" + else: + "unsupported ed25519 key" of PKScheme.ECDSA: - "secp256r1 key (" & ($key.eckey).shortLog & ")" + when supported(PKScheme.ECDSA): + "secp256r1 key (" & ($key.eckey).shortLog & ")" + else: + "unsupported secp256r1 key" of PKScheme.Secp256k1: - "secp256k1 key (" & ($key.skkey).shortLog & ")" - of PKScheme.NoSupport: - "not supported" + when supported(PKScheme.Secp256k1): + "secp256k1 key (" & ($key.skkey).shortLog & ")" + else: + "unsupported secp256k1 key" proc `$`*(sig: Signature): string = ## Get string representation of signature ``sig``. @@ -478,54 +718,74 @@ proc sign*(key: PrivateKey, var res: Signature case key.scheme: of PKScheme.RSA: - let sig = ? key.rsakey.sign(data).orError(SigError) - res.data = ? sig.getBytes().orError(SigError) - ok(res) + when supported(PKScheme.RSA): + let sig = ? key.rsakey.sign(data).orError(SigError) + res.data = ? sig.getBytes().orError(SigError) + ok(res) + else: + err(SchemeError) of PKScheme.Ed25519: - let sig = key.edkey.sign(data) - res.data = sig.getBytes() - ok(res) + when supported(PKScheme.Ed25519): + let sig = key.edkey.sign(data) + res.data = sig.getBytes() + ok(res) + else: + err(SchemeError) of PKScheme.ECDSA: - let sig = ? key.eckey.sign(data).orError(SigError) - res.data = ? sig.getBytes().orError(SigError) - ok(res) + when supported(PKScheme.ECDSA): + let sig = ? key.eckey.sign(data).orError(SigError) + res.data = ? sig.getBytes().orError(SigError) + ok(res) + else: + err(SchemeError) of PKScheme.Secp256k1: - let sig = key.skkey.sign(data) - res.data = sig.getBytes() - ok(res) - else: - err(SigError) + when supported(PKScheme.Secp256k1): + let sig = key.skkey.sign(data) + res.data = sig.getBytes() + ok(res) + else: + err(SchemeError) proc verify*(sig: Signature, message: openarray[byte], key: PublicKey): bool = ## Verify signature ``sig`` using message ``message`` and public key ``key``. ## Return ``true`` if message signature is valid. case key.scheme: of PKScheme.RSA: - var signature: RsaSignature - if signature.init(sig.data).isOk: - signature.verify(message, key.rsakey) + when supported(PKScheme.RSA): + var signature: RsaSignature + if signature.init(sig.data).isOk: + signature.verify(message, key.rsakey) + else: + false else: false of PKScheme.Ed25519: - var signature: EdSignature - if signature.init(sig.data): - signature.verify(message, key.edkey) + when supported(PKScheme.Ed25519): + var signature: EdSignature + if signature.init(sig.data): + signature.verify(message, key.edkey) + else: + false else: false of PKScheme.ECDSA: - var signature: EcSignature - if signature.init(sig.data).isOk: - signature.verify(message, key.eckey) + when supported(PKScheme.ECDSA): + var signature: EcSignature + if signature.init(sig.data).isOk: + signature.verify(message, key.eckey) + else: + false else: false of PKScheme.Secp256k1: - var signature: SkSignature - if signature.init(sig.data).isOk: - signature.verify(message, key.skkey) + when supported(PKScheme.Secp256k1): + var signature: SkSignature + if signature.init(sig.data).isOk: + signature.verify(message, key.skkey) + else: + false else: false - else: - false template makeSecret(buffer, hmactype, secret, seed: untyped) {.dirty.}= var ctx: hmactype @@ -565,9 +825,6 @@ proc stretchKeys*(cipherType: string, hashType: string, elif cipherType == "TwofishCTR": result.ivsize = twofish256.sizeBlock result.keysize = twofish256.sizeKey - elif cipherType == "BLOWFISH": - result.ivsize = 8 - result.keysize = 32 var seed = "key expansion" result.macsize = 20 @@ -614,7 +871,7 @@ proc mac*(secret: Secret, id: int): seq[byte] {.inline.} = proc ephemeral*( scheme: ECDHEScheme, - rng: var BrHmacDrbgContext): CryptoResult[KeyPair] = + rng: var BrHmacDrbgContext): CryptoResult[EcKeyPair] = ## Generate ephemeral keys used to perform ECDHE. var keypair: EcKeyPair if scheme == Secp256r1: @@ -623,12 +880,10 @@ proc ephemeral*( keypair = ? EcKeyPair.random(Secp384r1, rng).orError(KeyError) elif scheme == Secp521r1: keypair = ? EcKeyPair.random(Secp521r1, rng).orError(KeyError) - ok(KeyPair( - seckey: PrivateKey(scheme: ECDSA, eckey: keypair.seckey), - pubkey: PublicKey(scheme: ECDSA, eckey: keypair.pubkey))) + ok(EcKeyPair(keypair)) proc ephemeral*( - scheme: string, rng: var BrHmacDrbgContext): CryptoResult[KeyPair] = + scheme: string, rng: var BrHmacDrbgContext): CryptoResult[EcKeyPair] = ## Generate ephemeral keys used to perform ECDHE using string encoding. ## ## Currently supported encoding strings are P-256, P-384, P-521, if encoding @@ -642,33 +897,6 @@ proc ephemeral*( else: ephemeral(Secp521r1, rng) -proc makeSecret*(remoteEPublic: PublicKey, localEPrivate: PrivateKey, - data: var openarray[byte]): int = - ## Calculate shared secret using remote ephemeral public key - ## ``remoteEPublic`` and local ephemeral private key ``localEPrivate`` and - ## store shared secret to ``data``. - ## - ## Note this procedure supports only ECDSA keys. - ## - ## Returns number of bytes (octets) used to store shared secret data, or - ## ``0`` on error. - if remoteEPublic.scheme == ECDSA: - if localEPrivate.scheme == remoteEPublic.scheme: - result = toSecret(remoteEPublic.eckey, localEPrivate.eckey, data) - -proc getSecret*(remoteEPublic: PublicKey, - localEPrivate: PrivateKey): seq[byte] = - ## Calculate shared secret using remote ephemeral public key - ## ``remoteEPublic`` and local ephemeral private key ``localEPrivate`` and - ## store shared secret to ``data``. - ## - ## Note this procedure supports only ECDSA keys. - ## - ## Returns shared secret on success. - if remoteEPublic.scheme == ECDSA: - if localEPrivate.scheme == remoteEPublic.scheme: - result = getSecret(remoteEPublic.eckey, localEPrivate.eckey) - proc getOrder*(remotePubkey, localNonce: openarray[byte], localPubkey, remoteNonce: openarray[byte]): CryptoResult[int] = ## Compare values and calculate `order` parameter. @@ -707,14 +935,12 @@ proc selectBest*(order: int, p1, p2: string): string = s = strutils.split(p2, ",") else: var p = strutils.split(p1, ",") - result = p[0] - return + return p[0] for felement in f: for selement in s: if felement == selement: - result = felement - return + return felement proc createProposal*(nonce, pubkey: openarray[byte], exchanges, ciphers, hashes: string): seq[byte] = @@ -729,7 +955,7 @@ proc createProposal*(nonce, pubkey: openarray[byte], msg.write(4, ciphers) msg.write(5, hashes) msg.finish() - shallowCopy(result, msg.buffer) + msg.buffer proc decodeProposal*(message: seq[byte], nonce, pubkey: var seq[byte], exchanges, ciphers, hashes: var string): bool = @@ -757,7 +983,7 @@ proc createExchange*(epubkey, signature: openarray[byte]): seq[byte] = msg.write(1, epubkey) msg.write(2, signature) msg.finish() - shallowCopy(result, msg.buffer) + msg.buffer proc decodeExchange*(message: seq[byte], pubkey, signature: var seq[byte]): bool = diff --git a/libp2p/protocols/secure/secio.nim b/libp2p/protocols/secure/secio.nim index bbd3950a2..4cd2e6bc5 100644 --- a/libp2p/protocols/secure/secio.nim +++ b/libp2p/protocols/secure/secio.nim @@ -280,7 +280,7 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S remoteEBytesPubkey: seq[byte] remoteEBytesSig: seq[byte] remotePubkey: PublicKey - remoteEPubkey: PublicKey = PublicKey(scheme: ECDSA) + remoteEPubkey: ecnist.EcPublicKey remoteESignature: Signature remoteExchanges: string remoteCiphers: string @@ -317,7 +317,8 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S raise (ref SecioError)(msg: "Remote proposal decoding failed") if not remotePubkey.init(remoteBytesPubkey): - trace "Remote public key incorrect or corrupted", pubkey = remoteBytesPubkey.shortLog + trace "Remote public key incorrect or corrupted", + pubkey = remoteBytesPubkey.shortLog raise (ref SecioError)(msg: "Remote public key incorrect or corrupted") remotePeerId = PeerID.init(remotePubkey).tryGet() @@ -342,7 +343,7 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S var ekeypair = ephemeral(scheme, s.rng[]).tryGet() # We need EC public key in raw binary form - var epubkey = ekeypair.pubkey.eckey.getRawBytes().tryGet() + var epubkey = ekeypair.pubkey.getRawBytes().tryGet() var localCorpus = request[4..^1] & answer & epubkey var signature = s.localPrivateKey.sign(localCorpus).tryGet() @@ -370,16 +371,14 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S trace "Signature verified", scheme = remotePubkey.scheme - if not remoteEPubkey.eckey.initRaw(remoteEBytesPubkey): + if not remoteEPubkey.initRaw(remoteEBytesPubkey): trace "Remote ephemeral public key incorrect or corrupted", pubkey = toHex(remoteEBytesPubkey) raise (ref SecioError)(msg: "Remote ephemeral public key incorrect or corrupted") var secret = getSecret(remoteEPubkey, ekeypair.seckey) if len(secret) == 0: - trace "Shared secret could not be created", - pubkeyScheme = remoteEPubkey.scheme, - seckeyScheme = ekeypair.seckey.scheme + trace "Shared secret could not be created" raise (ref SecioError)(msg: "Shared secret could not be created") trace "Shared secret calculated", secret = secret.shortLog diff --git a/libp2p/standard_setup.nim b/libp2p/standard_setup.nim index 9ab8c262c..619c7d452 100644 --- a/libp2p/standard_setup.nim +++ b/libp2p/standard_setup.nim @@ -50,7 +50,7 @@ proc newStandardSwitch*(privKey = none(PrivateKey), raise (ref CatchableError)(msg: "Cannot initialize RNG") let - seckey = privKey.get(otherwise = PrivateKey.random(ECDSA, rng[]).tryGet()) + seckey = privKey.get(otherwise = PrivateKey.random(rng[]).tryGet()) peerInfo = PeerInfo.init(seckey, [address]) mplexProvider = newMuxerProvider(createMplex, MplexCodec) transports = @[Transport(TcpTransport.init(transportFlags))] diff --git a/tests/testpkifilter.nim b/tests/testpkifilter.nim new file mode 100644 index 000000000..e87641213 --- /dev/null +++ b/tests/testpkifilter.nim @@ -0,0 +1,239 @@ +## Nim-Libp2p +## Copyright (c) 2018 Status Research & Development GmbH +## Licensed under either of +## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +## * MIT license ([LICENSE-MIT](LICENSE-MIT)) +## at your option. +## This file may not be copied, modified, or distributed except according to +## those terms. +when defined(nimHasUsed): {.used.} + +import unittest +import ../libp2p/crypto/crypto +import nimcrypto/utils + +let rng = newRng() + +const ECDSA_PrivateKey = """ + 080312793077020101042070896381749FF6B30381C045F627C68C3062749BB53CB13 + 11FA07A7AEAB0A225A00A06082A8648CE3D030107A14403420004B17DAFF40C3221A5 + 0889A3FA9BB9DA4996AA1FE80D37358FBC6C88D89CD65738B4738C07CFD42F55293EB + 3A56DB224EDCD36E51076F43A63203F8936D868EF18 +""" +const ECDSA_PublicKey = """ + 0803125B3059301306072A8648CE3D020106082A8648CE3D03010703420004B17DAFF + 40C3221A50889A3FA9BB9DA4996AA1FE80D37358FBC6C88D89CD65738B4738C07CFD4 + 2F55293EB3A56DB224EDCD36E51076F43A63203F8936D868EF18 +""" +const SECP256k1_PrivateKey = """ + 080212209A0F994F5022D9D7B67ACEB26AA4D9F29B2628DBDCC28597469CB0049B6AB + 348 +""" +const SECP256k1_PublicKey = """ + 08021221039111FA29B374FE94B885408C45DF4647D09438C6E1F91F9B277A96CADD0 + 8A2B8 +""" +const ED25519_PrivateKey = """ + 08011240E1BFE38E35F9669CE77F6BE1A551560896B59A3F510537205F3AC1EDAD421 + 601C9D5C25AA2FC61B950976D6E5EC26425F8D4BFFE17169A4DE5A246B7154CB2B5 +""" +const ED25519_PublicKey = """ + 08011220C9D5C25AA2FC61B950976D6E5EC26425F8D4BFFE17169A4DE5A246B7154CB + 2B5 +""" +const RSA_PrivateKey = """ + 080012E80D308206E40201000282018100B5F2CABD05BE70474B262A2715B8C4FE74C + 6F628757FADB3F4815881CD9F8D3D2583757DF178B9BDCB207EB183A260934E6580C9 + 3B75789ACADAC13C9DD5A21A6BEDC4845A76D32F61F37C69B2C0E9D1161459FB1C93C + E13E3EA0436B82086DF4EC95860D910D32B134610C20E84834A4B9A40C5B4D6FB0732 + FF5332D8050221DA5101639044B6E2B18659E242FEEE58F4FF90BC9BEFF740E22C1A5 + 02774E4A0B103F750B829D6B1034908DB8338374EE2EF972A0E760DA9CC42F7D160CB + 33C4918308389CD7EF98D58378BB8CF8F8314131C6654903C704EE6BC069B223A39DE + 1CF1D5B0E34CE02522CFADF24AAF526445F7673CDE19F62C6D70266D1F7D03F98F9BD + 69C1BC78662BB9F52D90C2D1841680A9E6528E52BF2F83B84EC73D819240029A677F5 + AD8EF963843D36DB556B214E09A72B589FA139AFAED0EE5409AFFCAAEFC06329E2945 + A727E1AED64C1935F17F6F1E8FDD1B4AE69CACC3DAD8153059B5775A0A3B0EF38E3A1 + 8CFE3DB4338F53F03B6CA30E729A5EC510C68CE662902030100010282018012759C7E + 0AEC24460768CAD4064F25A54F41B44DAC8614A07249012AC22AD2D08652CD03C710E + 17F50F16E09227AC1E3900B9A425046FDC26E9C3D08A256BF4880F4B18060113821D1 + 853B7519CE9AAA3CDC39B8D1506992F9078FFFE134639A9A4AB12DBA380BC48E0308C + 63764D8511C547D07D1EE11AFCC4BBD2C266073B3ED8B5461BE8C4A25BBAF0EC576D8 + 9863EC0F55A6DD073E8595ACB5CAB60614FFFC95936CDC125A96C0E792FF7A53A4C0D + B2345A9DDA7BA81249912BD6A5D9355CD41A73B0E2A8D76ED7BB4D5B9AD98E5DD72CC + 0C01D55CF89ADC4DE4D7457BFFC88F7DBE0E0C77725920DFF7B37B05E47BF7E930584 + D8E3FD054189282EF5EF1882135FCEF02A709E4596C58D47B0A18AFD6C5ACE1C8074D + CEAE1693628623A98122D711DEF1D0BEC0E8FFD9D7BA3E3A0D9BF2E38FF240D255408 + 2D47E4D5120693CDF62D4C0A55BE170183FC6B363471FB04431BB0D4C00FD4A5B9D70 + F26CDE6842A1895C6E166289FFA2BDC81DF4FC32DC1C4E95C5AE9064E841C7C8F5BDB + 50281C100DE58C728695043A22FB9893CD659FDE3DFD9919BA70A758E2432E6043E35 + 49E7EF335D39D8A7DEF0FA9485B616C71758226E4003F6760E1A7975222E79C28BAD0 + D550D5750D0CE2B07ED90672BE130AA161D527F1012CED2013F7556E1B03BA0335501 + 3EDA0B3AE086D0A7825CBEB229C61999446042CC732F59DCB5E2502DF439AED0E77C4 + 218994FE78FAC6BD5E72AEFFECB29C7854D8CA0D39D7E68D0E78806413D0033E6AD20 + CFD36819EFFD53B7720BD3E938A1DEC9ADB4CF6CADD2BF7F0281C100D17CB4ED5777A + B4A5A609EC731643D6E981B8207BDB83803F1E1F6A6B51A3B79F0A25C77275C9840B7 + 4D91487E3FE91117CD0D9D68B13248A0656BFF616A22C57B18EBBE9F4AFE7DB1E5B38 + 07B23FBCDCC8215B196EBBED746109EDABF2F0359C82198D2C92145DE0598A2056333 + 52DBB59DBFF059E7C7754B99F9F0792FAB1519D3718D353498A460F468099E20075CF + 08211CD7668DBA1A77D7BDACFC91EC380E28B4851F13F1BD826FABBED060CFE1291D1 + 7C1861EF137C85F26EEB79AE570281C100C56F2B9974BA72F40750C6CE20C054340E4 + 791861773B023017DB8C5B7BF75DADF8A4A93DD106364B3FD4226085FCD18D3A9F66A + 0E6591EC6C415892D047B1E37E5D31B580EB88C6A909881A34DA876DE0A934E1E311F + 058860725587A9B14B7121DBF3762426A8B88EAAA73958B3784E485429576AC9A0305 + DED39F2650701DD742A5F9875AE1A0F154FB3CED9C48E2D5ACF8162736F53F9467940 + 7F566DAD0EC4CEDAFCA6661012BC9DB3C7CE0038077628D4F209C8BC9A5D752007CF1 + 105D0281C100C174F2F8C3EFC585B294CBCC943647ED1C173B2BBEEEA2FC31A2454F8 + AABA105694DE72A3A756E3D458A2282D9E4576DEB96F7DDC7D2EBE6DA090F85160717 + F95B46965EC1685640E9CA80CC43EBE51C16A2833A2F6FA21BD79E7DB4F11D8F70983 + B3E905A219A0E0109058708275B7B7EEB2157EB0EFAC9BD7982B1AA9874DBD5AFC88B + 68F91B85A1EBD3301E90E17BD8B7A58D22AE8F356821A0016026117CE6474FED078F4 + C828048EF002151972A03281A570985576D9D6F6D85357C779D0281C01065CEABF166 + FC360FB79BA436F2F6674BD641C0B502B1B071CD8D92BE582EE67FEB632306A2B94F4 + FC31F2D29CC57C9C422DA1A567C413100921E6B12C9D61E307F1364A021BCF323F6E5 + 0833D565FA1E886FC05370F2AAFC61256B98CA6D68B7F89C5FE90C026B53CC6E53826 + 9FE3350723F6205D9B1B8A6E5BFBEADD7B543FD7F0269E9CCFD00FE888D7012F53828 + E2DA931CBB692CAB71F5E14513451614A108F940DABFCD9BEAC4557EE503BD5196A21 + 522C61508521D7DB77A384BA696 +""" +const RSA_PublicKey = """ + 080012A603308201A2300D06092A864886F70D01010105000382018F003082018A028 + 2018100B5F2CABD05BE70474B262A2715B8C4FE74C6F628757FADB3F4815881CD9F8D + 3D2583757DF178B9BDCB207EB183A260934E6580C93B75789ACADAC13C9DD5A21A6BE + DC4845A76D32F61F37C69B2C0E9D1161459FB1C93CE13E3EA0436B82086DF4EC95860 + D910D32B134610C20E84834A4B9A40C5B4D6FB0732FF5332D8050221DA5101639044B + 6E2B18659E242FEEE58F4FF90BC9BEFF740E22C1A502774E4A0B103F750B829D6B103 + 4908DB8338374EE2EF972A0E760DA9CC42F7D160CB33C4918308389CD7EF98D58378B + B8CF8F8314131C6654903C704EE6BC069B223A39DE1CF1D5B0E34CE02522CFADF24AA + F526445F7673CDE19F62C6D70266D1F7D03F98F9BD69C1BC78662BB9F52D90C2D1841 + 680A9E6528E52BF2F83B84EC73D819240029A677F5AD8EF963843D36DB556B214E09A + 72B589FA139AFAED0EE5409AFFCAAEFC06329E2945A727E1AED64C1935F17F6F1E8FD + D1B4AE69CACC3DAD8153059B5775A0A3B0EF38E3A18CFE3DB4338F53F03B6CA30E729 + A5EC510C68CE66290203010001 +""" + +const + RSATestMessage = "RSA " & ( + when supported(PKScheme.RSA): "(enabled)" else: "(disabled)") & " test" + EcdsaTestMessage = "ECDSA " & ( + when supported(PKScheme.ECDSA): "(enabled)" else: "(disabled)") & " test" + EdTestMessage = "ED25519 " & ( + when supported(PKScheme.Ed25519): "(enabled)" else: "(disabled)") & " test" + SecpTestMessage = "SECP256k1 " & ( + when supported(PKScheme.Secp256k1): "(enabled)" else: "(disabled)") & " test" + +suite "Public key infrastructure filtering test suite": + test RSATestMessage: + when not(supported(PKScheme.RSA)): + let sk2048 = PrivateKey.random(PKScheme.RSA, rng[], 2048) + let sk3072 = PrivateKey.random(PKScheme.RSA, rng[], 3072) + let sk4096 = PrivateKey.random(PKScheme.RSA, rng[], 4096) + let kp2048 = KeyPair.random(PKScheme.RSA, rng[], 2048) + let kp3072 = KeyPair.random(PKScheme.RSA, rng[], 3072) + let kp4096 = KeyPair.random(PKScheme.RSA, rng[], 4096) + let sk = PrivateKey.init(fromHex(stripSpaces(RSA_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(RSA_PublicKey))) + check: + sk2048.isErr() == true + sk3072.isErr() == true + sk4096.isErr() == true + kp2048.isErr() == true + kp3072.isErr() == true + kp4096.isErr() == true + sk2048.error == CryptoError.SchemeError + sk3072.error == CryptoError.SchemeError + sk4096.error == CryptoError.SchemeError + kp2048.error == CryptoError.SchemeError + kp3072.error == CryptoError.SchemeError + kp4096.error == CryptoError.SchemeError + sk.isErr() == true + pk.isErr() == true + sk.error == CryptoError.KeyError + pk.error == CryptoError.KeyError + else: + let sk2048 = PrivateKey.random(PKScheme.RSA, rng[], 2048) + let kp2048 = KeyPair.random(PKScheme.RSA, rng[], 2048) + let sk = PrivateKey.init(fromHex(stripSpaces(RSA_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(RSA_PublicKey))) + check: + sk2048.isOk() == true + kp2048.isOk() == true + sk.isOk() == true + pk.isOk() == true + + test EcdsaTestMessage: + when not(supported(PKScheme.ECDSA)): + let rsk = PrivateKey.random(PKScheme.ECDSA, rng[]) + let rkp = KeyPair.random(PKScheme.ECDSA, rng[]) + let sk = PrivateKey.init(fromHex(stripSpaces(ECDSA_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(ECDSA_PublicKey))) + check: + rsk.isErr() == true + rkp.isErr() == true + rsk.error == CryptoError.SchemeError + rkp.error == CryptoError.SchemeError + sk.isErr() == true + pk.isErr() == true + sk.error == CryptoError.KeyError + pk.error == CryptoError.KeyError + else: + let rsk = PrivateKey.random(PKScheme.ECDSA, rng[]) + let rkp = KeyPair.random(PKScheme.ECDSA, rng[]) + let sk = PrivateKey.init(fromHex(stripSpaces(ECDSA_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(ECDSA_PublicKey))) + check: + rsk.isOk() == true + rkp.isOk() == true + sk.isOk() == true + pk.isOk() == true + + test EdTestMessage: + when not(supported(PKScheme.Ed25519)): + let rsk = PrivateKey.random(PKScheme.Ed25519, rng[]) + let rkp = KeyPair.random(PKScheme.Ed25519, rng[]) + let sk = PrivateKey.init(fromHex(stripSpaces(ED25519_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(ED25519_PublicKey))) + check: + rsk.isErr() == true + rkp.isErr() == true + rsk.error == CryptoError.SchemeError + rkp.error == CryptoError.SchemeError + sk.isErr() == true + pk.isErr() == true + sk.error == CryptoError.KeyError + pk.error == CryptoError.KeyError + else: + let rsk = PrivateKey.random(PKScheme.Ed25519, rng[]) + let rkp = KeyPair.random(PKScheme.Ed25519, rng[]) + let sk = PrivateKey.init(fromHex(stripSpaces(ED25519_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(ED25519_PublicKey))) + check: + rsk.isOk() == true + rkp.isOk() == true + sk.isOk() == true + pk.isOk() == true + + test SecpTestMessage: + when not(supported(PKScheme.Secp256k1)): + let rsk = PrivateKey.random(PKScheme.Secp256k1, rng[]) + let rkp = KeyPair.random(PKScheme.Secp256k1, rng[]) + let sk = PrivateKey.init(fromHex(stripSpaces(SECP256k1_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(SECP256k1_PublicKey))) + check: + rsk.isErr() == true + rkp.isErr() == true + rsk.error == CryptoError.SchemeError + rkp.error == CryptoError.SchemeError + sk.isErr() == true + pk.isErr() == true + sk.error == CryptoError.KeyError + pk.error == CryptoError.KeyError + else: + let rsk = PrivateKey.random(PKScheme.Secp256k1, rng[]) + let rkp = KeyPair.random(PKScheme.Secp256k1, rng[]) + let sk = PrivateKey.init(fromHex(stripSpaces(SECP256k1_PrivateKey))) + let pk = PublicKey.init(fromHex(stripSpaces(SECP256k1_PublicKey))) + check: + rsk.isOk() == true + rkp.isOk() == true + sk.isOk() == true + pk.isOk() == true