From 1c4d72f5e361851cc16b618fe66f1707931113da Mon Sep 17 00:00:00 2001 From: Giovanni Petrantoni Date: Thu, 23 Apr 2020 21:10:20 +0900 Subject: [PATCH] Use Result construct in minasn1 (#144) --- libp2p/crypto/crypto.nim | 14 +-- libp2p/crypto/ecnist.nim | 117 ++++++++++++------------ libp2p/crypto/minasn1.nim | 141 +++++++++++++---------------- libp2p/crypto/rsa.nim | 183 ++++++++++++++++++-------------------- tests/testecnist.nim | 25 +++--- tests/testrsa.nim | 32 +++---- 6 files changed, 240 insertions(+), 272 deletions(-) diff --git a/libp2p/crypto/crypto.nim b/libp2p/crypto/crypto.nim index 1a21bd385..ec5de7ffc 100644 --- a/libp2p/crypto/crypto.nim +++ b/libp2p/crypto/crypto.nim @@ -12,6 +12,8 @@ import rsa, ecnist, ed25519/ed25519, secp import ../protobuf/minprotobuf, ../vbuffer, ../multihash, ../multicodec import nimcrypto/[rijndael, blowfish, twofish, sha, sha2, hash, hmac, utils] import ../utility +import stew/results +export results # This is workaround for Nim's `import` bug export rijndael, blowfish, twofish, sha, sha2, hash, hmac, utils @@ -263,7 +265,7 @@ proc init*(key: var PrivateKey, data: openarray[byte]): bool = var scheme = cast[PKScheme](cast[int8](id)) var nkey = PrivateKey(scheme: scheme) if scheme == RSA: - if init(nkey.rsakey, buffer) == Asn1Status.Success: + if init(nkey.rsakey, buffer).isOk: key = nkey result = true elif scheme == Ed25519: @@ -271,7 +273,7 @@ proc init*(key: var PrivateKey, data: openarray[byte]): bool = key = nkey result = true elif scheme == ECDSA: - if init(nkey.eckey, buffer) == Asn1Status.Success: + if init(nkey.eckey, buffer).isOk: key = nkey result = true elif scheme == Secp256k1: @@ -294,7 +296,7 @@ proc init*(key: var PublicKey, data: openarray[byte]): bool = var scheme = cast[PKScheme](cast[int8](id)) var nkey = PublicKey(scheme: scheme) if scheme == RSA: - if init(nkey.rsakey, buffer) == Asn1Status.Success: + if init(nkey.rsakey, buffer).isOk: key = nkey result = true elif scheme == Ed25519: @@ -302,7 +304,7 @@ proc init*(key: var PublicKey, data: openarray[byte]): bool = key = nkey result = true elif scheme == ECDSA: - if init(nkey.eckey, buffer) == Asn1Status.Success: + if init(nkey.eckey, buffer).isOk: key = nkey result = true elif scheme == Secp256k1: @@ -484,7 +486,7 @@ proc verify*(sig: Signature, message: openarray[byte], ## Return ``true`` if message signature is valid. if key.scheme == RSA: var signature: RsaSignature - if signature.init(sig.data) == Asn1Status.Success: + if signature.init(sig.data).isOk: result = signature.verify(message, key.rsakey) elif key.scheme == Ed25519: var signature: EdSignature @@ -492,7 +494,7 @@ proc verify*(sig: Signature, message: openarray[byte], result = signature.verify(message, key.edkey) elif key.scheme == ECDSA: var signature: EcSignature - if signature.init(sig.data) == Asn1Status.Success: + if signature.init(sig.data).isOk: result = signature.verify(message, key.eckey) elif key.scheme == Secp256k1: var signature: SkSignature diff --git a/libp2p/crypto/ecnist.nim b/libp2p/crypto/ecnist.nim index e8faa4ce4..645e9556e 100644 --- a/libp2p/crypto/ecnist.nim +++ b/libp2p/crypto/ecnist.nim @@ -17,7 +17,9 @@ import bearssl import nimcrypto/utils import minasn1 -export minasn1.Asn1Status +export minasn1.Asn1Error +import stew/results +export results const PubKey256Length* = 65 @@ -529,43 +531,39 @@ proc `==`*(sig1, sig2: EcSignature): bool = else: result = (sig1.buffer == sig2.buffer) -proc init*(key: var EcPrivateKey, data: openarray[byte]): Asn1Status = +proc init*(key: var EcPrivateKey, data: openarray[byte]): Result[void, Asn1Error] = ## Initialize EC `private key` or `signature` ``key`` from ASN.1 DER binary ## representation ``data``. ## - ## Procedure returns ``Asn1Status``. + ## Procedure returns ``Result[void, Asn1Error]``. var raw, oid, field: Asn1Field var curve: cint var ab = Asn1Buffer.init(data) - result = ab.read(field) - if result != Asn1Status.Success: - return + field = ? ab.read() + if field.kind != Asn1Tag.Sequence: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) var ib = field.getBuffer() - result = ib.read(field) - if result != Asn1Status.Success: - return + field = ? ib.read() + if field.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if field.vint != 1'u64: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + raw = ? ib.read() - result = ib.read(raw) - if result != Asn1Status.Success: - return if raw.kind != Asn1Tag.OctetString: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + oid = ? ib.read() - result = ib.read(oid) - if result != Asn1Status.Success: - return if oid.kind != Asn1Tag.Oid: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if oid == Asn1OidSecp256r1: curve = cast[cint](Secp256r1) @@ -574,7 +572,7 @@ proc init*(key: var EcPrivateKey, data: openarray[byte]): Asn1Status = elif oid == Asn1OidSecp521r1: curve = cast[cint](Secp521r1) else: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if checkScalar(raw.toOpenArray(), curve) == 1'u32: key = new EcPrivateKey @@ -583,47 +581,44 @@ proc init*(key: var EcPrivateKey, data: openarray[byte]): Asn1Status = key.key.x = cast[ptr cuchar](addr key.buffer[0]) key.key.xlen = raw.length key.key.curve = curve - result = Asn1Status.Success + ok() else: - result = Asn1Status.Incorrect + err(Asn1Error.Incorrect) -proc init*(pubkey: var EcPublicKey, data: openarray[byte]): Asn1Status = +proc init*(pubkey: var EcPublicKey, data: openarray[byte]): Result[void, Asn1Error] = ## Initialize EC public key ``pubkey`` from ASN.1 DER binary representation ## ``data``. ## - ## Procedure returns ``Asn1Status``. + ## Procedure returns ``Result[void, Asn1Error]``. var raw, oid, field: Asn1Field var curve: cint var ab = Asn1Buffer.init(data) - result = ab.read(field) - if result != Asn1Status.Success: - return + + field = ? ab.read() + if field.kind != Asn1Tag.Sequence: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) var ib = field.getBuffer() - result = ib.read(field) - if result != Asn1Status.Success: - return + field = ? ib.read() + if field.kind != Asn1Tag.Sequence: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) var ob = field.getBuffer() - result = ob.read(oid) - if result != Asn1Status.Success: - return + oid = ? ob.read() + if oid.kind != Asn1Tag.Oid: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if oid != Asn1OidEcPublicKey: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + oid = ? ob.read() - result = ob.read(oid) - if result != Asn1Status.Success: - return if oid.kind != Asn1Tag.Oid: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if oid == Asn1OidSecp256r1: curve = cast[cint](Secp256r1) @@ -632,13 +627,12 @@ proc init*(pubkey: var EcPublicKey, data: openarray[byte]): Asn1Status = elif oid == Asn1OidSecp521r1: curve = cast[cint](Secp521r1) else: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + raw = ? ib.read() - result = ib.read(raw) - if result != Asn1Status.Success: - return if raw.kind != Asn1Tag.BitString: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if checkPublic(raw.toOpenArray(), curve) != 0: pubkey = new EcPublicKey @@ -647,50 +641,51 @@ proc init*(pubkey: var EcPublicKey, data: openarray[byte]): Asn1Status = pubkey.key.q = cast[ptr cuchar](addr pubkey.buffer[0]) pubkey.key.qlen = raw.length pubkey.key.curve = curve - result = Asn1Status.Success + ok() else: - result = Asn1Status.Incorrect + err(Asn1Error.Incorrect) -proc init*(sig: var EcSignature, data: openarray[byte]): Asn1Status = +proc init*(sig: var EcSignature, data: openarray[byte]): Result[void, Asn1Error] = ## Initialize EC signature ``sig`` from raw binary representation ``data``. ## - ## Procedure returns ``Asn1Status``. - result = Asn1Status.Incorrect + ## Procedure returns ``Result[void, Asn1Error]``. if len(data) > 0: sig = new EcSignature sig.buffer = @data - result = Asn1Status.Success + ok() + else: + err(Asn1Error.Incorrect) -proc init*[T: EcPKI](sospk: var T, data: string): Asn1Status {.inline.} = +proc init*[T: EcPKI](sospk: var T, data: string): Result[void, Asn1Error] {.inline.} = ## Initialize EC `private key`, `public key` or `signature` ``sospk`` from ## ASN.1 DER hexadecimal string representation ``data``. ## ## Procedure returns ``Asn1Status``. - result = sospk.init(fromHex(data)) + sospk.init(fromHex(data)) proc init*(t: typedesc[EcPrivateKey], data: openarray[byte]): EcPrivateKey = ## Initialize EC private key from ASN.1 DER binary representation ``data`` and ## return constructed object. let res = result.init(data) - if res != Asn1Status.Success: + if res.isErr: raise newException(EcKeyIncorrectError, - "Incorrect private key (" & $res & ")") + "Incorrect private key (" & $res.error & ")") proc init*(t: typedesc[EcPublicKey], data: openarray[byte]): EcPublicKey = ## Initialize EC public key from ASN.1 DER binary representation ``data`` and ## return constructed object. let res = result.init(data) - if res != Asn1Status.Success: + if res.isErr: raise newException(EcKeyIncorrectError, - "Incorrect public key (" & $res & ")") + "Incorrect public key (" & $res.error & ")") proc init*(t: typedesc[EcSignature], data: openarray[byte]): EcSignature = ## Initialize EC signature from raw binary representation ``data`` and ## return constructed object. let res = result.init(data) - if res != Asn1Status.Success: + if res.isErr: raise newException(EcKeyIncorrectError, - "Incorrect signature (" & $res & ")") + "Incorrect signature (" & $res.error & ")") proc init*[T: EcPKI](t: typedesc[T], data: string): T {.inline.} = ## Initialize EC `private key`, `public key` or `signature` from hexadecimal diff --git a/libp2p/crypto/minasn1.nim b/libp2p/crypto/minasn1.nim index dd5afefb4..a8bc6e03a 100644 --- a/libp2p/crypto/minasn1.nim +++ b/libp2p/crypto/minasn1.nim @@ -8,13 +8,17 @@ ## those terms. ## This module implements minimal ASN.1 encoding/decoding primitives. -import stew/endians2 + +{.push raises: [Defect].} + +import stew/[endians2, results] +export results import nimcrypto/utils type - Asn1Status* {.pure.} = enum + Asn1Error* {.pure.} = enum + None, Error, - Success, Overflow, Incomplete, Indefinite, @@ -22,6 +26,8 @@ type NoSupport, Overrun + Asn1Result*[T] = Result[T, Asn1Error] + Asn1Class* {.pure.} = enum Universal = 0x00, Application = 0x01 @@ -406,54 +412,51 @@ proc asn1EncodeContextTag*(dest: var openarray[byte], value: openarray[byte], copyMem(addr dest[1], addr buffer[0], lenlen) copyMem(addr dest[1 + lenlen], unsafeAddr value[0], len(value)) -proc getLength(ab: var Asn1Buffer, length: var uint64): Asn1Status = +proc getLength(ab: var Asn1Buffer): Asn1Result[uint64] = ## Decode length part of ASN.1 TLV triplet. - result = Asn1Status.Incomplete if not ab.isEmpty(): let b = ab.buffer[ab.offset] if (b and 0x80'u8) == 0x00'u8: - length = cast[uint64](b) + let length = cast[uint64](b) ab.offset += 1 - result = Asn1Status.Success - return + return ok(length) if b == 0x80'u8: - length = 0'u64 - result = Asn1Status.Indefinite - return + return err(Asn1Error.Indefinite) if b == 0xFF'u8: - length = 0'u64 - result = Asn1Status.Incorrect - return + return err(Asn1Error.Incorrect) let octets = cast[uint64](b and 0x7F'u8) if octets > 8'u64: - length = 0'u64 - result = Asn1Status.Overflow - return - length = 0'u64 + return err(Asn1Error.Overflow) if ab.isEnough(int(octets)): + var length: uint64 = 0 for i in 0..= 0 and c < 4: - klass = cast[Asn1Class](c) + return ok(length) else: - return Asn1Status.Incorrect + return err(Asn1Error.Incomplete) + else: + return err(Asn1Error.Incomplete) + +proc getTag(ab: var Asn1Buffer, tag: var int): Asn1Result[Asn1Class] = + ## Decode tag part of ASN.1 TLV triplet. + if not ab.isEmpty(): + let + b = ab.buffer[ab.offset] + c = int((b and 0xC0'u8) shr 6) tag = int(b and 0x3F) ab.offset += 1 - result = Asn1Status.Success + if c >= 0 and c < 4: + ok(cast[Asn1Class](c)) + else: + err(Asn1Error.Incorrect) + else: + err(Asn1Error.Incomplete) -proc read*(ab: var Asn1Buffer, field: var Asn1Field): Asn1Status = +proc read*(ab: var Asn1Buffer): Asn1Result[Asn1Field] = ## Decode value part of ASN.1 TLV triplet. var + field: Asn1Field tag, ttag, offset: int length, tlength: uint64 klass: Asn1Class @@ -462,55 +465,44 @@ proc read*(ab: var Asn1Buffer, field: var Asn1Field): Asn1Status = inclass = false while true: offset = ab.offset - result = ab.getTag(tag, klass) - if result != Asn1Status.Success: - break + klass = ? ab.getTag(tag) if klass == Asn1Class.ContextSpecific: if inclass: - result = Asn1Status.Incorrect - break + return err(Asn1Error.Incorrect) + inclass = true ttag = tag - result = ab.getLength(tlength) - if result != Asn1Status.Success: - break + tlength = ? ab.getLength() elif klass == Asn1Class.Universal: - result = ab.getLength(length) - if result != Asn1Status.Success: - break + length = ? ab.getLength() if inclass: if length >= tlength: - result = Asn1Status.Incorrect - break + return err(Asn1Error.Incorrect) if cast[byte](tag) == Asn1Tag.Boolean.code(): # BOOLEAN if length != 1: - result = Asn1Status.Incorrect - break + return err(Asn1Error.Incorrect) if not ab.isEnough(cast[int](length)): - result = Asn1Status.Incomplete - break + return err(Asn1Error.Incomplete) let b = ab.buffer[ab.offset] if b != 0xFF'u8 and b != 0x00'u8: - result = Asn1Status.Incorrect - break + return err(Asn1Error.Incorrect) + field = Asn1Field(kind: Asn1Tag.Boolean, klass: klass, index: ttag, offset: cast[int](ab.offset), length: 1) shallowCopy(field.buffer, ab.buffer) field.vbool = (b == 0xFF'u8) ab.offset += 1 - result = Asn1Status.Success - break + return ok(field) elif cast[byte](tag) == Asn1Tag.Integer.code(): # INTEGER if not ab.isEnough(cast[int](length)): - result = Asn1Status.Incomplete - break + return err(Asn1Error.Incomplete) if ab.buffer[ab.offset] == 0x00'u8: length -= 1 ab.offset += 1 @@ -523,77 +515,64 @@ proc read*(ab: var Asn1Buffer, field: var Asn1Field): Asn1Status = field.vint = (field.vint shl 8) or cast[uint64](ab.buffer[ab.offset + i]) ab.offset += cast[int](length) - result = Asn1Status.Success - break + return ok(field) elif cast[byte](tag) == Asn1Tag.BitString.code(): # BIT STRING if not ab.isEnough(cast[int](length)): - result = Asn1Status.Incomplete - break + return err(Asn1Error.Incomplete) field = Asn1Field(kind: Asn1Tag.BitString, klass: klass, index: ttag, offset: cast[int](ab.offset + 1), length: cast[int](length - 1)) shallowCopy(field.buffer, ab.buffer) field.ubits = cast[int](((length - 1) shl 3) - ab.buffer[ab.offset]) ab.offset += cast[int](length) - result = Asn1Status.Success - break + return ok(field) elif cast[byte](tag) == Asn1Tag.OctetString.code(): # OCT STRING if not ab.isEnough(cast[int](length)): - result = Asn1Status.Incomplete - break + return err(Asn1Error.Incomplete) field = Asn1Field(kind: Asn1Tag.OctetString, klass: klass, index: ttag, offset: cast[int](ab.offset), length: cast[int](length)) shallowCopy(field.buffer, ab.buffer) ab.offset += cast[int](length) - result = Asn1Status.Success - break + return ok(field) elif cast[byte](tag) == Asn1Tag.Null.code(): # NULL if length != 0: - result = Asn1Status.Incorrect - break + return err(Asn1Error.Incorrect) field = Asn1Field(kind: Asn1Tag.Null, klass: klass, index: ttag, offset: cast[int](ab.offset), length: 0) shallowCopy(field.buffer, ab.buffer) ab.offset += cast[int](length) - result = Asn1Status.Success - break + return ok(field) elif cast[byte](tag) == Asn1Tag.Oid.code(): # OID if not ab.isEnough(cast[int](length)): - result = Asn1Status.Incomplete - break + return err(Asn1Error.Incomplete) field = Asn1Field(kind: Asn1Tag.Oid, klass: klass, index: ttag, offset: cast[int](ab.offset), length: cast[int](length)) shallowCopy(field.buffer, ab.buffer) ab.offset += cast[int](length) - result = Asn1Status.Success - break + return ok(field) elif cast[byte](tag) == Asn1Tag.Sequence.code(): # SEQUENCE if not ab.isEnough(cast[int](length)): - result = Asn1Status.Incomplete - break + return err(Asn1Error.Incomplete) field = Asn1Field(kind: Asn1Tag.Sequence, klass: klass, index: ttag, offset: cast[int](ab.offset), length: cast[int](length)) shallowCopy(field.buffer, ab.buffer) ab.offset += cast[int](length) - result = Asn1Status.Success - break + return ok(field) else: - result = Asn1Status.NoSupport - break + return err(Asn1Error.NoSupport) inclass = false ttag = 0 else: - result = Asn1Status.NoSupport - break + return err(Asn1Error.NoSupport) proc getBuffer*(field: Asn1Field): Asn1Buffer = ## Return ``field`` as Asn1Buffer to enter composite types. diff --git a/libp2p/crypto/rsa.nim b/libp2p/crypto/rsa.nim index 46d70e14b..79be34e2a 100644 --- a/libp2p/crypto/rsa.nim +++ b/libp2p/crypto/rsa.nim @@ -15,7 +15,9 @@ import nimcrypto/utils import bearssl import minasn1 -export Asn1Status +export Asn1Error +import stew/results +export results const DefaultPublicExponent* = 3'u32 @@ -379,7 +381,7 @@ proc getBytes*(sig: RsaSignature): seq[byte] = else: raise newException(RsaSignatureError, "Incorrect signature") -proc init*(key: var RsaPrivateKey, data: openarray[byte]): Asn1Status = +proc init*(key: var RsaPrivateKey, data: openarray[byte]): Result[void, Asn1Error] = ## Initialize RSA private key ``key`` from ASN.1 DER binary representation ## ``data``. ## @@ -387,71 +389,63 @@ proc init*(key: var RsaPrivateKey, data: openarray[byte]): Asn1Status = var field, rawn, rawpube, rawprie, rawp, rawq, rawdp, rawdq, rawiq: Asn1Field + # Asn1Field is not trivial so avoid too much Result + var ab = Asn1Buffer.init(data) - result = ab.read(field) - if result != Asn1Status.Success: - return + field = ? ab.read() + if field.kind != Asn1Tag.Sequence: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) var ib = field.getBuffer() - result = ib.read(field) - if result != Asn1Status.Success: - return + field = ? ib.read() + if field.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if field.vint != 0'u64: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawn = ? ib.read() - result = ib.read(rawn) - if result != Asn1Status.Success: - return if rawn.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawpube = ? ib.read() - result = ib.read(rawpube) - if result != Asn1Status.Success: - return if rawpube.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawprie = ? ib.read() - result = ib.read(rawprie) - if result != Asn1Status.Success: - return if rawprie.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawp = ? ib.read() - result = ib.read(rawp) - if result != Asn1Status.Success: - return if rawp.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawq = ? ib.read() - result = ib.read(rawq) - if result != Asn1Status.Success: - return if rawq.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawdp = ? ib.read() - result = ib.read(rawdp) - if result != Asn1Status.Success: - return if rawdp.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawdq = ? ib.read() - result = ib.read(rawdq) - if result != Asn1Status.Success: - return if rawdq.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawiq = ? ib.read() - result = ib.read(rawiq) - if result != Asn1Status.Success: - return if rawiq.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) if len(rawn) >= (MinKeySize shr 3) and len(rawp) > 0 and len(rawq) > 0 and len(rawdp) > 0 and len(rawdq) > 0 and len(rawiq) > 0: @@ -474,11 +468,11 @@ proc init*(key: var RsaPrivateKey, data: openarray[byte]): Asn1Status = key.seck.iqlen = len(rawiq) key.pexplen = len(rawprie) key.seck.nBitlen = cast[uint32](len(rawn) shl 3) - result = Asn1Status.Success + ok() else: - result = Asn1Status.Incorrect + err(Asn1Error.Incorrect) -proc init*(key: var RsaPublicKey, data: openarray[byte]): Asn1Status = +proc init*(key: var RsaPublicKey, data: openarray[byte]): Result[void, Asn1Error] = ## Initialize RSA public key ``key`` from ASN.1 DER binary representation ## ``data``. ## @@ -486,59 +480,55 @@ proc init*(key: var RsaPublicKey, data: openarray[byte]): Asn1Status = var field, rawn, rawe: Asn1Field var ab = Asn1Buffer.init(data) - result = ab.read(field) - if result != Asn1Status.Success: - return + field = ? ab.read() + if field.kind != Asn1Tag.Sequence: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + var ib = field.getBuffer() - result = ib.read(field) - if result != Asn1Status.Success: - return + field = ? ib.read() + if field.kind != Asn1Tag.Sequence: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + var ob = field.getBuffer() - result = ob.read(field) - if result != Asn1Status.Success: - return + field = ? ob.read() + if field.kind != Asn1Tag.Oid: - return Asn1Status.Incorrect - if field != Asn1OidRsaEncryption: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + elif field != Asn1OidRsaEncryption: + return err(Asn1Error.Incorrect) + + field = ? ob.read() - result = ob.read(field) - if result != Asn1Status.Success: - return if field.kind != Asn1Tag.Null: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + field = ? ib.read() - result = ib.read(field) - if result != Asn1Status.Success: - return if field.kind != Asn1Tag.BitString: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + var vb = field.getBuffer() - result = vb.read(field) - if result != Asn1Status.Success: - return + field = ? vb.read() + if field.kind != Asn1Tag.Sequence: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + var sb = field.getBuffer() - result = sb.read(rawn) - if result != Asn1Status.Success: - return - if rawn.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + rawn = ? sb.read() - result = sb.read(rawe) - if result != Asn1Status.Success: - return if rawn.kind != Asn1Tag.Integer: - return Asn1Status.Incorrect + return err(Asn1Error.Incorrect) + + rawe = ? sb.read() + + if rawe.kind != Asn1Tag.Integer: + return err(Asn1Error.Incorrect) if len(rawn) >= (MinKeySize shr 3) and len(rawe) > 0: key = new RsaPublicKey @@ -547,51 +537,52 @@ proc init*(key: var RsaPublicKey, data: openarray[byte]): Asn1Status = key.key.e = cast[ptr cuchar](addr key.buffer[rawe.offset]) key.key.nlen = len(rawn) key.key.elen = len(rawe) - result = Asn1Status.Success + ok() else: - result = Asn1Status.Incorrect + err(Asn1Error.Incorrect) -proc init*(sig: var RsaSignature, data: openarray[byte]): Asn1Status = +proc init*(sig: var RsaSignature, data: openarray[byte]): Result[void, Asn1Error] = ## Initialize RSA signature ``sig`` from ASN.1 DER binary representation ## ``data``. ## - ## Procedure returns ``Asn1Status``. - result = Asn1Status.Incorrect + ## Procedure returns ``Result[void, Asn1Status]``. if len(data) > 0: sig = new RsaSignature sig.buffer = @data - result = Asn1Status.Success + ok() + else: + err(Asn1Error.Incorrect) -proc init*[T: RsaPKI](sospk: var T, data: string): Asn1Status {.inline.} = +proc init*[T: RsaPKI](sospk: var T, data: string): Result[void, Asn1Error] {.inline.} = ## Initialize EC `private key`, `public key` or `scalar` ``sospk`` from ## hexadecimal string representation ``data``. ## - ## Procedure returns ``Asn1Status``. - result = sospk.init(fromHex(data)) + ## Procedure returns ``Result[void, Asn1Status]``. + sospk.init(fromHex(data)) proc init*(t: typedesc[RsaPrivateKey], data: openarray[byte]): RsaPrivateKey = ## Initialize RSA private key from ASN.1 DER binary representation ``data`` ## and return constructed object. let res = result.init(data) - if res != Asn1Status.Success: + if res.isErr: raise newException(RsaKeyIncorrectError, - "Incorrect private key (" & $res & ")") + "Incorrect private key (" & $res.error & ")") proc init*(t: typedesc[RsaPublicKey], data: openarray[byte]): RsaPublicKey = ## Initialize RSA public key from ASN.1 DER binary representation ``data`` ## and return constructed object. let res = result.init(data) - if res != Asn1Status.Success: + if res.isErr: raise newException(RsaKeyIncorrectError, - "Incorrect public key (" & $res & ")") + "Incorrect public key (" & $res.error & ")") proc init*(t: typedesc[RsaSignature], data: openarray[byte]): RsaSignature = ## Initialize RSA signature from raw binary representation ``data`` and ## return constructed object. let res = result.init(data) - if res != Asn1Status.Success: + if res.isErr: raise newException(RsaKeyIncorrectError, - "Incorrect signature (" & $res & ")") + "Incorrect signature (" & $res.error & ")") proc init*[T: RsaPKI](t: typedesc[T], data: string): T {.inline.} = ## Initialize RSA `private key`, `public key` or `signature` from hexadecimal diff --git a/tests/testecnist.nim b/tests/testecnist.nim index 15b4b1469..6932b4527 100644 --- a/tests/testecnist.nim +++ b/tests/testecnist.nim @@ -9,6 +9,7 @@ import unittest import nimcrypto/utils import ../libp2p/crypto/ecnist +import stew/results when defined(nimHasUsed): {.used.} @@ -304,8 +305,8 @@ suite "EC NIST-P256/384/521 test suite": check: key.toBytes(skey2) > 0 check: - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk + rkey2.init(skey2).isOk var rkey3 = EcPrivateKey.init(skey1) var rkey4 = EcPrivateKey.init(skey2) check: @@ -322,8 +323,8 @@ suite "EC NIST-P256/384/521 test suite": var skey1 = pair.pubkey.getBytes() check: pair.pubkey.toBytes(skey2) > 0 - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk + rkey2.init(skey2).isOk var rkey3 = EcPublicKey.init(skey1) var rkey4 = EcPublicKey.init(skey2) check: @@ -411,8 +412,8 @@ suite "EC NIST-P256/384/521 test suite": check: key.toBytes(skey2) > 0 check: - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk + rkey2.init(skey2).isOk var rkey3 = EcPrivateKey.init(skey1) var rkey4 = EcPrivateKey.init(skey2) check: @@ -429,8 +430,8 @@ suite "EC NIST-P256/384/521 test suite": var skey1 = pair.pubkey.getBytes() check: pair.pubkey.toBytes(skey2) > 0 - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk + rkey2.init(skey2).isOk var rkey3 = EcPublicKey.init(skey1) var rkey4 = EcPublicKey.init(skey2) check: @@ -518,8 +519,8 @@ suite "EC NIST-P256/384/521 test suite": check: key.toBytes(skey2) > 0 check: - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk + rkey2.init(skey2).isOk var rkey3 = EcPrivateKey.init(skey1) var rkey4 = EcPrivateKey.init(skey2) check: @@ -536,8 +537,8 @@ suite "EC NIST-P256/384/521 test suite": var skey1 = pair.pubkey.getBytes() check: pair.pubkey.toBytes(skey2) > 0 - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk + rkey2.init(skey2).isOk var rkey3 = EcPublicKey.init(skey1) var rkey4 = EcPublicKey.init(skey2) check: diff --git a/tests/testrsa.nim b/tests/testrsa.nim index fd6afceb8..9f4661ee8 100644 --- a/tests/testrsa.nim +++ b/tests/testrsa.nim @@ -277,8 +277,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = key.getBytes() check key.toBytes(skey2) > 0 check: - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPrivateKey.init(skey1) var rkey4 = RsaPrivateKey.init(skey2) check: @@ -295,8 +295,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = key.getBytes() check key.toBytes(skey2) > 0 check: - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPrivateKey.init(skey1) var rkey4 = RsaPrivateKey.init(skey2) check: @@ -312,8 +312,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = key.getBytes() check key.toBytes(skey2) > 0 check: - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPrivateKey.init(skey1) var rkey4 = RsaPrivateKey.init(skey2) check: @@ -331,8 +331,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = key.getBytes() check key.toBytes(skey2) > 0 check: - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPrivateKey.init(skey1) var rkey4 = RsaPrivateKey.init(skey2) check: @@ -349,8 +349,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = pair.pubkey().getBytes() check: pair.pubkey.toBytes(skey2) > 0 - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPublicKey.init(skey1) var rkey4 = RsaPublicKey.init(skey2) check: @@ -367,8 +367,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = pair.pubkey.getBytes() check: pair.pubkey.toBytes(skey2) > 0 - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPublicKey.init(skey1) var rkey4 = RsaPublicKey.init(skey2) check: @@ -384,8 +384,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = pair.pubkey.getBytes() check: pair.pubkey.toBytes(skey2) > 0 - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPublicKey.init(skey1) var rkey4 = RsaPublicKey.init(skey2) check: @@ -402,8 +402,8 @@ suite "RSA 512/1024/2048/4096 test suite": var skey1 = pair.pubkey.getBytes() check: pair.pubkey.toBytes(skey2) > 0 - rkey1.init(skey1) == Asn1Status.Success - rkey2.init(skey2) == Asn1Status.Success + rkey1.init(skey1).isOk() + rkey2.init(skey2).isOk() var rkey3 = RsaPublicKey.init(skey1) var rkey4 = RsaPublicKey.init(skey2) check: