Skip to content

Commit 08a48fa

Browse files
authored
{.async: (raises).} annotations for protocols/secure (#1059)
1 parent 61b299e commit 08a48fa

File tree

3 files changed

+210
-137
lines changed

3 files changed

+210
-137
lines changed

libp2p/protocols/secure/noise.nim

+73-34
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ proc encrypt(
142142

143143
inc state.n
144144
if state.n > NonceMax:
145-
raise newException(NoiseNonceMaxError, "Noise max nonce value reached")
145+
raise (ref NoiseNonceMaxError)(msg: "Noise max nonce value reached")
146146

147147
proc encryptWithAd(state: var CipherState, ad, data: openArray[byte]): seq[byte]
148148
{.raises: [NoiseNonceMaxError].} =
@@ -168,10 +168,11 @@ proc decryptWithAd(state: var CipherState, ad, data: openArray[byte]): seq[byte]
168168
trace "decryptWithAd", tagIn = tagIn.shortLog, tagOut = tagOut.shortLog, nonce = state.n
169169
if tagIn != tagOut:
170170
debug "decryptWithAd failed", data = shortLog(data)
171-
raise newException(NoiseDecryptTagError, "decryptWithAd failed tag authentication.")
171+
raise (ref NoiseDecryptTagError)(msg:
172+
"decryptWithAd failed tag authentication.")
172173
inc state.n
173174
if state.n > NonceMax:
174-
raise newException(NoiseNonceMaxError, "Noise max nonce value reached")
175+
raise (ref NoiseNonceMaxError)(msg: "Noise max nonce value reached")
175176

176177
# Symmetricstate
177178

@@ -181,8 +182,7 @@ proc init(_: type[SymmetricState]): SymmetricState =
181182
result.cs = CipherState(k: EmptyKey)
182183

183184
proc mixKey(ss: var SymmetricState, ikm: ChaChaPolyKey) =
184-
var
185-
temp_keys: array[2, ChaChaPolyKey]
185+
var temp_keys: array[2, ChaChaPolyKey]
186186
sha256.hkdf(ss.ck, ikm, [], temp_keys)
187187
ss.ck = temp_keys[0]
188188
ss.cs = CipherState(k: temp_keys[1])
@@ -198,8 +198,7 @@ proc mixHash(ss: var SymmetricState, data: openArray[byte]) =
198198

199199
# We might use this for other handshake patterns/tokens
200200
proc mixKeyAndHash(ss: var SymmetricState, ikm: openArray[byte]) {.used.} =
201-
var
202-
temp_keys: array[3, ChaChaPolyKey]
201+
var temp_keys: array[3, ChaChaPolyKey]
203202
sha256.hkdf(ss.ck, ikm, [], temp_keys)
204203
ss.ck = temp_keys[0]
205204
ss.mixHash(temp_keys[1])
@@ -234,7 +233,8 @@ proc init(_: type[HandshakeState]): HandshakeState =
234233

235234
template write_e: untyped =
236235
trace "noise write e"
237-
# Sets e (which must be empty) to GENERATE_KEYPAIR(). Appends e.public_key to the buffer. Calls MixHash(e.public_key).
236+
# Sets e (which must be empty) to GENERATE_KEYPAIR().
237+
# Appends e.public_key to the buffer. Calls MixHash(e.public_key).
238238
hs.e = genKeyPair(p.rng[])
239239
msg.add hs.e.publicKey
240240
hs.ss.mixHash(hs.e.publicKey)
@@ -275,26 +275,28 @@ template read_e: untyped =
275275
trace "noise read e", size = msg.len
276276

277277
if msg.len < Curve25519Key.len:
278-
raise newException(NoiseHandshakeError, "Noise E, expected more data")
278+
raise (ref NoiseHandshakeError)(msg: "Noise E, expected more data")
279279

280-
# Sets re (which must be empty) to the next DHLEN bytes from the message. Calls MixHash(re.public_key).
280+
# Sets re (which must be empty) to the next DHLEN bytes from the message.
281+
# Calls MixHash(re.public_key).
281282
hs.re[0..Curve25519Key.high] = msg.toOpenArray(0, Curve25519Key.high)
282283
msg.consume(Curve25519Key.len)
283284
hs.ss.mixHash(hs.re)
284285

285286
template read_s: untyped =
286287
trace "noise read s", size = msg.len
287-
# Sets temp to the next DHLEN + 16 bytes of the message if HasKey() == True, or to the next DHLEN bytes otherwise.
288+
# Sets temp to the next DHLEN + 16 bytes of the message if HasKey() == True,
289+
# or to the next DHLEN bytes otherwise.
288290
# Sets rs (which must be empty) to DecryptAndHash(temp).
289291
let
290292
rsLen =
291293
if hs.ss.cs.hasKey:
292294
if msg.len < Curve25519Key.len + ChaChaPolyTag.len:
293-
raise newException(NoiseHandshakeError, "Noise S, expected more data")
295+
raise (ref NoiseHandshakeError)(msg: "Noise S, expected more data")
294296
Curve25519Key.len + ChaChaPolyTag.len
295297
else:
296298
if msg.len < Curve25519Key.len:
297-
raise newException(NoiseHandshakeError, "Noise S, expected more data")
299+
raise (ref NoiseHandshakeError)(msg: "Noise S, expected more data")
298300
Curve25519Key.len
299301
hs.rs[0..Curve25519Key.high] =
300302
hs.ss.decryptAndHash(msg.toOpenArray(0, rsLen - 1))
@@ -315,7 +317,11 @@ proc readFrame(
315317
await sconn.readExactly(addr buffer[0], buffer.len)
316318
return buffer
317319

318-
proc writeFrame(sconn: Connection, buf: openArray[byte]): Future[void] =
320+
proc writeFrame(
321+
sconn: Connection,
322+
buf: openArray[byte]
323+
): Future[void] {.async: (raises: [
324+
CancelledError, LPStreamError], raw: true).} =
319325
doAssert buf.len <= uint16.high.int
320326
var
321327
lesize = buf.len.uint16
@@ -326,13 +332,24 @@ proc writeFrame(sconn: Connection, buf: openArray[byte]): Future[void] =
326332
outbuf &= buf
327333
sconn.write(outbuf)
328334

329-
proc receiveHSMessage(sconn: Connection): Future[seq[byte]] = readFrame(sconn)
330-
proc sendHSMessage(sconn: Connection, buf: openArray[byte]): Future[void] =
335+
proc receiveHSMessage(
336+
sconn: Connection
337+
): Future[seq[byte]] {.async: (raises: [
338+
CancelledError, LPStreamError], raw: true).} =
339+
readFrame(sconn)
340+
341+
proc sendHSMessage(
342+
sconn: Connection,
343+
buf: openArray[byte]
344+
): Future[void] {.async: (raises: [
345+
CancelledError, LPStreamError], raw: true).} =
331346
writeFrame(sconn, buf)
332347

333348
proc handshakeXXOutbound(
334349
p: Noise, conn: Connection,
335-
p2pSecret: seq[byte]): Future[HandshakeResult] {.async.} =
350+
p2pSecret: seq[byte]
351+
): Future[HandshakeResult] {.async: (raises: [
352+
CancelledError, LPStreamError]).} =
336353
const initiator = true
337354
var
338355
hs = HandshakeState.init()
@@ -374,13 +391,16 @@ proc handshakeXXOutbound(
374391
await conn.sendHSMessage(msg.data)
375392

376393
let (cs1, cs2) = hs.ss.split()
377-
return HandshakeResult(cs1: cs1, cs2: cs2, remoteP2psecret: remoteP2psecret, rs: hs.rs)
394+
return HandshakeResult(
395+
cs1: cs1, cs2: cs2, remoteP2psecret: remoteP2psecret, rs: hs.rs)
378396
finally:
379397
burnMem(hs)
380398

381399
proc handshakeXXInbound(
382400
p: Noise, conn: Connection,
383-
p2pSecret: seq[byte]): Future[HandshakeResult] {.async.} =
401+
p2pSecret: seq[byte]
402+
): Future[HandshakeResult] {.async: (raises: [
403+
CancelledError, LPStreamError]).} =
384404
const initiator = false
385405

386406
var
@@ -424,7 +444,8 @@ proc handshakeXXInbound(
424444
let
425445
remoteP2psecret = hs.ss.decryptAndHash(msg.data)
426446
(cs1, cs2) = hs.ss.split()
427-
return HandshakeResult(cs1: cs1, cs2: cs2, remoteP2psecret: remoteP2psecret, rs: hs.rs)
447+
return HandshakeResult(
448+
cs1: cs1, cs2: cs2, remoteP2psecret: remoteP2psecret, rs: hs.rs)
428449
finally:
429450
burnMem(hs)
430451

@@ -486,7 +507,8 @@ method write*(
486507
try:
487508
encryptFrame(
488509
sconn,
489-
cipherFrames.toOpenArray(woffset, woffset + chunkSize + FramingSize - 1),
510+
cipherFrames.toOpenArray(
511+
woffset, woffset + chunkSize + FramingSize - 1),
490512
message.toOpenArray(offset, offset + chunkSize - 1))
491513
except NoiseNonceMaxError as exc:
492514
debug "Noise nonce exceeded"
@@ -509,21 +531,28 @@ method write*(
509531
# sequencing issues
510532
sconn.stream.write(cipherFrames)
511533

512-
method handshake*(p: Noise, conn: Connection, initiator: bool, peerId: Opt[PeerId]): Future[SecureConn] {.async.} =
534+
method handshake*(
535+
p: Noise,
536+
conn: Connection,
537+
initiator: bool,
538+
peerId: Opt[PeerId]
539+
): Future[SecureConn] {.async: (raises: [CancelledError, LPStreamError]).} =
513540
trace "Starting Noise handshake", conn, initiator
514541

515542
let timeout = conn.timeout
516543
conn.timeout = HandshakeTimeout
517544

518545
# https://github.com/libp2p/specs/tree/master/noise#libp2p-data-in-handshake-messages
519-
let
520-
signedPayload = p.localPrivateKey.sign(
521-
PayloadString & p.noiseKeys.publicKey.getBytes).tryGet()
546+
let signedPayload = p.localPrivateKey.sign(
547+
PayloadString & p.noiseKeys.publicKey.getBytes)
548+
if signedPayload.isErr():
549+
raise (ref NoiseHandshakeError)(msg:
550+
"Failed to sign public key: " & $signedPayload.error())
522551

523552
var
524553
libp2pProof = initProtoBuffer()
525554
libp2pProof.write(1, p.localPublicKey)
526-
libp2pProof.write(2, signedPayload.getBytes())
555+
libp2pProof.write(2, signedPayload.get().getBytes())
527556
# data field also there but not used!
528557
libp2pProof.finish()
529558

@@ -542,29 +571,38 @@ method handshake*(p: Noise, conn: Connection, initiator: bool, peerId: Opt[PeerI
542571
remoteSigBytes: seq[byte]
543572

544573
if not remoteProof.getField(1, remotePubKeyBytes).valueOr(false):
545-
raise newException(NoiseHandshakeError, "Failed to deserialize remote public key bytes. (initiator: " & $initiator & ")")
574+
raise (ref NoiseHandshakeError)(msg:
575+
"Failed to deserialize remote public key bytes. (initiator: " &
576+
$initiator & ")")
546577
if not remoteProof.getField(2, remoteSigBytes).valueOr(false):
547-
raise newException(NoiseHandshakeError, "Failed to deserialize remote signature bytes. (initiator: " & $initiator & ")")
578+
raise (ref NoiseHandshakeError)(msg:
579+
"Failed to deserialize remote signature bytes. (initiator: " &
580+
$initiator & ")")
548581

549582
if not remotePubKey.init(remotePubKeyBytes):
550-
raise newException(NoiseHandshakeError, "Failed to decode remote public key. (initiator: " & $initiator & ")")
583+
raise (ref NoiseHandshakeError)(msg:
584+
"Failed to decode remote public key. (initiator: " & $initiator & ")")
551585
if not remoteSig.init(remoteSigBytes):
552-
raise newException(NoiseHandshakeError, "Failed to decode remote signature. (initiator: " & $initiator & ")")
586+
raise (ref NoiseHandshakeError)(msg:
587+
"Failed to decode remote signature. (initiator: " & $initiator & ")")
553588

554589
let verifyPayload = PayloadString & handshakeRes.rs.getBytes
555590
if not remoteSig.verify(verifyPayload, remotePubKey):
556-
raise newException(NoiseHandshakeError, "Noise handshake signature verify failed.")
591+
raise (ref NoiseHandshakeError)(msg:
592+
"Noise handshake signature verify failed.")
557593
else:
558594
trace "Remote signature verified", conn
559595

560596
let pid = PeerId.init(remotePubKey).valueOr:
561-
raise newException(NoiseHandshakeError, "Invalid remote peer id: " & $error)
597+
raise (ref NoiseHandshakeError)(msg:
598+
"Invalid remote peer id: " & $error)
562599

563600
trace "Remote peer id", pid = $pid
564601

565602
peerId.withValue(targetPid):
566603
if not targetPid.validate():
567-
raise newException(NoiseHandshakeError, "Failed to validate expected peerId.")
604+
raise (ref NoiseHandshakeError)(msg:
605+
"Failed to validate expected peerId.")
568606

569607
if pid != targetPid:
570608
var
@@ -574,7 +612,8 @@ method handshake*(p: Noise, conn: Connection, initiator: bool, peerId: Opt[PeerI
574612
initiator, dealt_peer = conn,
575613
dealt_key = $failedKey, received_peer = $pid,
576614
received_key = $remotePubKey
577-
raise newException(NoiseHandshakeError, "Noise handshake, peer id don't match! " & $pid & " != " & $targetPid)
615+
raise (ref NoiseHandshakeError)(msg:
616+
"Noise handshake, peer id don't match! " & $pid & " != " & $targetPid)
578617
conn.peerId = pid
579618

580619
var tmp = NoiseConnection.new(conn, conn.peerId, conn.observedAddr)

0 commit comments

Comments
 (0)