formatting

This commit is contained in:
Diego 2024-10-03 17:09:34 +02:00
parent b1e115475a
commit 5b7ea1c9a4
No known key found for this signature in database
GPG Key ID: C9DAC9BF68D1F806
2 changed files with 92 additions and 87 deletions

View File

@ -36,9 +36,9 @@ const
P2P_SIGNING_PREFIX = "libp2p-tls-handshake:" P2P_SIGNING_PREFIX = "libp2p-tls-handshake:"
SIGNATURE_ALG = MBEDTLS_MD_SHA256 SIGNATURE_ALG = MBEDTLS_MD_SHA256
EC_GROUP_ID = MBEDTLS_ECP_DP_SECP256R1 EC_GROUP_ID = MBEDTLS_ECP_DP_SECP256R1
LIBP2P_EXT_OID_DER: array[10, byte] = [ LIBP2P_EXT_OID_DER: array[10, byte] =
0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0xA2, 0x5A, 0x01, 0x01 [0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0xA2, 0x5A, 0x01, 0x01]
] # "1.3.6.1.4.1.53594.1.1" # "1.3.6.1.4.1.53594.1.1"
# Exception types for TLS certificate errors # Exception types for TLS certificate errors
type type
@ -64,7 +64,9 @@ proc ptrInc*(p: ptr byte, n: uint): ptr byte =
## Utility function to increment a pointer by n bytes. ## Utility function to increment a pointer by n bytes.
cast[ptr byte](cast[uint](p) + n) cast[ptr byte](cast[uint](p) + n)
proc generateSignedKey(signature: seq[byte], pubKey: seq[byte]): seq[byte] {.raises: [ASN1EncodingError].} = proc generateSignedKey(
signature: seq[byte], pubKey: seq[byte]
): seq[byte] {.raises: [ASN1EncodingError].} =
## Generates the ASN.1-encoded SignedKey structure. ## Generates the ASN.1-encoded SignedKey structure.
## ##
## The SignedKey structure contains the public key and its signature, ## The SignedKey structure contains the public key and its signature,
@ -79,8 +81,7 @@ proc generateSignedKey(signature: seq[byte], pubKey: seq[byte]): seq[byte] {.rai
## ##
## Raises: ## Raises:
## - `ASN1EncodingError` if ASN.1 encoding fails. ## - `ASN1EncodingError` if ASN.1 encoding fails.
const const extValueSize = 256 # Buffer size for ASN.1 encoding
extValueSize = 256 # Buffer size for ASN.1 encoding
var var
extValue: array[extValueSize, byte] extValue: array[extValueSize, byte]
extPtr: ptr byte = addr extValue[extValueSize - 1] # Start at the end of the buffer extPtr: ptr byte = addr extValue[extValueSize - 1] # Start at the end of the buffer
@ -89,10 +90,7 @@ proc generateSignedKey(signature: seq[byte], pubKey: seq[byte]): seq[byte] {.rai
# Write signature OCTET STRING # Write signature OCTET STRING
let retSig = mbedtls_asn1_write_octet_string( let retSig = mbedtls_asn1_write_octet_string(
addr extPtr, addr extPtr, startPtr, unsafeAddr signature[0], signature.len.uint
startPtr,
unsafeAddr signature[0],
signature.len.uint
) )
if retSig < 0: if retSig < 0:
raise newException(ASN1EncodingError, "Failed to write signature OCTET STRING") raise newException(ASN1EncodingError, "Failed to write signature OCTET STRING")
@ -100,10 +98,7 @@ proc generateSignedKey(signature: seq[byte], pubKey: seq[byte]): seq[byte] {.rai
# Write publicKey OCTET STRING # Write publicKey OCTET STRING
let retPub = mbedtls_asn1_write_octet_string( let retPub = mbedtls_asn1_write_octet_string(
addr extPtr, addr extPtr, startPtr, unsafeAddr pubKey[0], pubKey.len.uint
startPtr,
unsafeAddr pubKey[0],
pubKey.len.uint
) )
if retPub < 0: if retPub < 0:
raise newException(ASN1EncodingError, "Failed to write publicKey OCTET STRING") raise newException(ASN1EncodingError, "Failed to write publicKey OCTET STRING")
@ -112,20 +107,14 @@ proc generateSignedKey(signature: seq[byte], pubKey: seq[byte]): seq[byte] {.rai
# Total length of the SEQUENCE contents # Total length of the SEQUENCE contents
let contentLen = retSig + retPub let contentLen = retSig + retPub
# Write SEQUENCE length # Write SEQUENCE length
let retLen = mbedtls_asn1_write_len( let retLen = mbedtls_asn1_write_len(addr extPtr, startPtr, contentLen.uint)
addr extPtr,
startPtr,
contentLen.uint
)
if retLen < 0: if retLen < 0:
raise newException(ASN1EncodingError, "Failed to write SEQUENCE length") raise newException(ASN1EncodingError, "Failed to write SEQUENCE length")
len += retLen len += retLen
# Write SEQUENCE tag # Write SEQUENCE tag
let retTag = mbedtls_asn1_write_tag( let retTag = mbedtls_asn1_write_tag(
addr extPtr, addr extPtr, startPtr, MBEDTLS_ASN1_CONSTRUCTED or MBEDTLS_ASN1_SEQUENCE
startPtr,
MBEDTLS_ASN1_CONSTRUCTED or MBEDTLS_ASN1_SEQUENCE
) )
if retTag < 0: if retTag < 0:
raise newException(ASN1EncodingError, "Failed to write SEQUENCE tag") raise newException(ASN1EncodingError, "Failed to write SEQUENCE tag")
@ -142,7 +131,12 @@ proc generateSignedKey(signature: seq[byte], pubKey: seq[byte]): seq[byte] {.rai
proc makeLibp2pExtension( proc makeLibp2pExtension(
identityKeypair: KeyPair, certificateKeypair: mbedtls_pk_context identityKeypair: KeyPair, certificateKeypair: mbedtls_pk_context
): seq[byte] {.raises: [CertificateCreationError, IdentityPubKeySerializationError, IdentitySigningError, ASN1EncodingError, TLSCertificateError].} = ): seq[byte] {.
raises: [
CertificateCreationError, IdentityPubKeySerializationError, IdentitySigningError,
ASN1EncodingError, TLSCertificateError,
]
.} =
## Creates the libp2p extension containing the SignedKey. ## Creates the libp2p extension containing the SignedKey.
## ##
## The libp2p extension is an ASN.1-encoded structure that includes ## The libp2p extension is an ASN.1-encoded structure that includes
@ -167,16 +161,15 @@ proc makeLibp2pExtension(
certPubKeyDerLen: cint certPubKeyDerLen: cint
certPubKeyDerLen = mbedtls_pk_write_pubkey_der( certPubKeyDerLen = mbedtls_pk_write_pubkey_der(
unsafeAddr certificateKeypair, unsafeAddr certificateKeypair, addr certPubKeyDer[0], certPubKeyDer.len.uint
addr certPubKeyDer[0],
certPubKeyDer.len.uint
) )
if certPubKeyDerLen < 0: if certPubKeyDerLen < 0:
raise newException(CertificateCreationError, "Failed to write certificate public key in DER format") raise newException(
CertificateCreationError, "Failed to write certificate public key in DER format"
)
# Adjust pointer to the start of the data # Adjust pointer to the start of the data
let certPubKeyDerPtr = let certPubKeyDerPtr = addr certPubKeyDer[certPubKeyDer.len - certPubKeyDerLen]
addr certPubKeyDer[certPubKeyDer.len - certPubKeyDerLen]
# Create the Message to Sign # Create the Message to Sign
var msg = newSeq[byte](P2P_SIGNING_PREFIX.len + certPubKeyDerLen.int.int) var msg = newSeq[byte](P2P_SIGNING_PREFIX.len + certPubKeyDerLen.int.int)
@ -186,16 +179,12 @@ proc makeLibp2pExtension(
msg[i] = byte(P2P_SIGNING_PREFIX[i]) msg[i] = byte(P2P_SIGNING_PREFIX[i])
# Copy the public key DER into msg # Copy the public key DER into msg
copyMem( copyMem(addr msg[P2P_SIGNING_PREFIX.len], certPubKeyDerPtr, certPubKeyDerLen.int)
addr msg[P2P_SIGNING_PREFIX.len],
certPubKeyDerPtr,
certPubKeyDerLen.int
)
# Compute SHA-256 hash of the message # Compute SHA-256 hash of the message
var hash: array[32, byte] var hash: array[32, byte]
let hashRet = mbedtls_sha256( let hashRet = mbedtls_sha256(
msg[0].addr, msg.len.uint, addr hash[0], 0 # 0 for SHA-256 msg[0].addr, msg.len.uint, addr hash[0], 0 # 0 for SHA-256
) )
if hashRet != 0: if hashRet != 0:
# Since hashing failure is critical and unlikely, we can raise a general exception # Since hashing failure is critical and unlikely, we can raise a general exception
@ -204,20 +193,30 @@ proc makeLibp2pExtension(
# Sign the hash with the Identity Key # Sign the hash with the Identity Key
let signatureResult = identityKeypair.seckey.sign(hash) let signatureResult = identityKeypair.seckey.sign(hash)
if signatureResult.isErr: if signatureResult.isErr:
raise newException(IdentitySigningError, "Failed to sign the hash with the identity key") raise newException(
IdentitySigningError, "Failed to sign the hash with the identity key"
)
let signature = signatureResult.get().data let signature = signatureResult.get().data
# Get the public key bytes # Get the public key bytes
let pubKeyBytesResult = identityKeypair.pubkey.getBytes() let pubKeyBytesResult = identityKeypair.pubkey.getBytes()
if pubKeyBytesResult.isErr: if pubKeyBytesResult.isErr:
raise newException(IdentityPubKeySerializationError, "Failed to get identity public key bytes") raise newException(
IdentityPubKeySerializationError, "Failed to get identity public key bytes"
)
let pubKeyBytes = pubKeyBytesResult.get() let pubKeyBytes = pubKeyBytesResult.get()
# Generate the SignedKey ASN.1 structure # Generate the SignedKey ASN.1 structure
return generateSignedKey(signature, pubKeyBytes) return generateSignedKey(signature, pubKeyBytes)
proc generate*(identityKeyPair: KeyPair): (seq[byte], seq[byte]) proc generate*(
{.raises: [KeyGenerationError, CertificateCreationError, ASN1EncodingError, IdentityPubKeySerializationError, IdentitySigningError, TLSCertificateError].} = identityKeyPair: KeyPair
): (seq[byte], seq[byte]) {.
raises: [
KeyGenerationError, CertificateCreationError, ASN1EncodingError,
IdentityPubKeySerializationError, IdentitySigningError, TLSCertificateError,
]
.} =
## Generates a self-signed X.509 certificate with the libp2p extension. ## Generates a self-signed X.509 certificate with the libp2p extension.
## ##
## Parameters: ## Parameters:
@ -258,29 +257,26 @@ proc generate*(identityKeyPair: KeyPair): (seq[byte], seq[byte])
mbedtls_entropy_func, mbedtls_entropy_func,
addr entropy, addr entropy,
cast[ptr byte](personalization.cstring), cast[ptr byte](personalization.cstring),
personalization.len.uint personalization.len.uint,
) )
if ret != 0: if ret != 0:
raise newException(KeyGenerationError, "Failed to seed CTR_DRBG") raise newException(KeyGenerationError, "Failed to seed CTR_DRBG")
# Initialize certificate key # Initialize certificate key
ret = mbedtls_pk_setup( ret = mbedtls_pk_setup(addr certKey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))
addr certKey,
mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)
)
if ret != 0: if ret != 0:
raise newException(KeyGenerationError, "Failed to set up certificate key context") raise newException(KeyGenerationError, "Failed to set up certificate key context")
# Generate key pair for the certificate # Generate key pair for the certificate
let G = try: let G =
mb_pk_ec(certKey) try:
except MbedTLSError as e: mb_pk_ec(certKey)
raise newException(KeyGenerationError, e.msg) except MbedTLSError as e:
ret = mbedtls_ecp_gen_key( raise newException(KeyGenerationError, e.msg)
EC_GROUP_ID, G, mbedtls_ctr_drbg_random, addr ctrDrbg ret = mbedtls_ecp_gen_key(EC_GROUP_ID, G, mbedtls_ctr_drbg_random, addr ctrDrbg)
)
if ret != 0: if ret != 0:
raise newException(KeyGenerationError, "Failed to generate EC key pair for certificate") raise
newException(KeyGenerationError, "Failed to generate EC key pair for certificate")
## Initialize libp2p extension ## Initialize libp2p extension
let libp2pExtension = makeLibp2pExtension(identityKeyPair, certKey) let libp2pExtension = makeLibp2pExtension(identityKeyPair, certKey)
@ -297,15 +293,16 @@ proc generate*(identityKeyPair: KeyPair): (seq[byte], seq[byte])
# Set Validity Period # Set Validity Period
let notBefore = "19750101000000" let notBefore = "19750101000000"
let notAfter = "40960101000000" let notAfter = "40960101000000"
ret = mbedtls_x509write_crt_set_validity( ret =
addr crt, notBefore.cstring, notAfter.cstring mbedtls_x509write_crt_set_validity(addr crt, notBefore.cstring, notAfter.cstring)
)
if ret != 0: if ret != 0:
raise newException(CertificateCreationError, "Failed to set certificate validity period") raise newException(
CertificateCreationError, "Failed to set certificate validity period"
)
# Assign the Public Key to the Certificate # Assign the Public Key to the Certificate
mbedtls_x509write_crt_set_subject_key(addr crt, addr certKey) mbedtls_x509write_crt_set_subject_key(addr crt, addr certKey)
mbedtls_x509write_crt_set_issuer_key(addr crt, addr certKey) # Self-signed mbedtls_x509write_crt_set_issuer_key(addr crt, addr certKey) # Self-signed
# Add the libp2p Extension # Add the libp2p Extension
let oid = string.fromBytes(LIBP2P_EXT_OID_DER) let oid = string.fromBytes(LIBP2P_EXT_OID_DER)
@ -318,7 +315,9 @@ proc generate*(identityKeyPair: KeyPair): (seq[byte], seq[byte])
libp2pExtension.len.uint, # Extension data length libp2pExtension.len.uint, # Extension data length
) )
if ret != 0: if ret != 0:
raise newException(CertificateCreationError, "Failed to set libp2p extension in certificate") raise newException(
CertificateCreationError, "Failed to set libp2p extension in certificate"
)
# Set Basic Constraints (optional, e.g., CA:FALSE) # Set Basic Constraints (optional, e.g., CA:FALSE)
ret = mbedtls_x509write_crt_set_basic_constraints( ret = mbedtls_x509write_crt_set_basic_constraints(
@ -351,15 +350,16 @@ proc generate*(identityKeyPair: KeyPair): (seq[byte], seq[byte])
addr certBuffer[0], addr certBuffer[0],
CERT_BUFFER_SIZE.uint, CERT_BUFFER_SIZE.uint,
mbedtls_ctr_drbg_random, mbedtls_ctr_drbg_random,
addr ctrDrbg addr ctrDrbg,
) )
if certLen < 0: if certLen < 0:
raise newException(CertificateCreationError, "Failed to write certificate in DER format") raise newException(
CertificateCreationError, "Failed to write certificate in DER format"
)
# Adjust the buffer to contain only the DER data # Adjust the buffer to contain only the DER data
let certificateDer = toSeq(certBuffer[ let certificateDer =
(CERT_BUFFER_SIZE - certLen) ..< CERT_BUFFER_SIZE toSeq(certBuffer[(CERT_BUFFER_SIZE - certLen) ..< CERT_BUFFER_SIZE])
])
# Serialize the Private Key in DER Format (PKCS#8) # Serialize the Private Key in DER Format (PKCS#8)
var var
@ -370,21 +370,25 @@ proc generate*(identityKeyPair: KeyPair): (seq[byte], seq[byte])
addr certKey, addr privKeyBuffer[0], privKeyBuffer.len.uint addr certKey, addr privKeyBuffer[0], privKeyBuffer.len.uint
) )
if privKeyLen < 0: if privKeyLen < 0:
raise newException(CertificateCreationError, "Failed to write private key in DER format") raise newException(
CertificateCreationError, "Failed to write private key in DER format"
)
# Adjust the buffer to contain only the DER data # Adjust the buffer to contain only the DER data
let privateKeyDer = toSeq(privKeyBuffer[ let privateKeyDer =
(privKeyBuffer.len - privKeyLen) ..< privKeyBuffer.len toSeq(privKeyBuffer[(privKeyBuffer.len - privKeyLen) ..< privKeyBuffer.len])
])
# Return the Serialized Certificate and Private Key # Return the Serialized Certificate and Private Key
return (certificateDer, privateKeyDer) return (certificateDer, privateKeyDer)
proc libp2pext( proc libp2pext(
p_ctx: pointer; crt: ptr mbedtls_x509_crt; p_ctx: pointer,
oid: ptr mbedtls_x509_buf; critical: cint; crt: ptr mbedtls_x509_crt,
p: ptr byte; endPtr: ptr byte oid: ptr mbedtls_x509_buf,
): cint {.cdecl.} = critical: cint,
p: ptr byte,
endPtr: ptr byte,
): cint {.cdecl.} =
## Callback function to parse the libp2p extension. ## Callback function to parse the libp2p extension.
## ##
## This function is used as a callback by mbedtls during certificate parsing ## This function is used as a callback by mbedtls during certificate parsing
@ -403,27 +407,26 @@ proc libp2pext(
# Check if the OID matches the libp2p extension # Check if the OID matches the libp2p extension
if oid.len != LIBP2P_EXT_OID_DER.len: if oid.len != LIBP2P_EXT_OID_DER.len:
return MBEDTLS_ERR_OID_NOT_FOUND # Extension not handled by this callback return MBEDTLS_ERR_OID_NOT_FOUND # Extension not handled by this callback
for i in 0 ..< LIBP2P_EXT_OID_DER.len: for i in 0 ..< LIBP2P_EXT_OID_DER.len:
if ptrInc(oid.p, i.uint)[] != LIBP2P_EXT_OID_DER[i]: if ptrInc(oid.p, i.uint)[] != LIBP2P_EXT_OID_DER[i]:
return MBEDTLS_ERR_OID_NOT_FOUND # Extension not handled by this callback return MBEDTLS_ERR_OID_NOT_FOUND # Extension not handled by this callback
var parsePtr = p var parsePtr = p
# Parse SEQUENCE tag and length # Parse SEQUENCE tag and length
var len: uint var len: uint
if mbedtls_asn1_get_tag( if mbedtls_asn1_get_tag(
addr parsePtr, endPtr, addr len, addr parsePtr, endPtr, addr len, MBEDTLS_ASN1_CONSTRUCTED or MBEDTLS_ASN1_SEQUENCE
MBEDTLS_ASN1_CONSTRUCTED or MBEDTLS_ASN1_SEQUENCE ) != 0:
) != 0:
debug "Failed to parse SEQUENCE in libp2p extension" debug "Failed to parse SEQUENCE in libp2p extension"
return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
# Parse publicKey OCTET STRING # Parse publicKey OCTET STRING
var pubKeyLen: uint var pubKeyLen: uint
if mbedtls_asn1_get_tag( if mbedtls_asn1_get_tag(
addr parsePtr, endPtr, addr pubKeyLen, MBEDTLS_ASN1_OCTET_STRING addr parsePtr, endPtr, addr pubKeyLen, MBEDTLS_ASN1_OCTET_STRING
) != 0: ) != 0:
debug "Failed to parse publicKey OCTET STRING in libp2p extension" debug "Failed to parse publicKey OCTET STRING in libp2p extension"
return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
@ -432,12 +435,11 @@ proc libp2pext(
copyMem(addr publicKey[0], parsePtr, int(pubKeyLen)) copyMem(addr publicKey[0], parsePtr, int(pubKeyLen))
parsePtr = ptrInc(parsePtr, pubKeyLen) parsePtr = ptrInc(parsePtr, pubKeyLen)
# Parse signature OCTET STRING # Parse signature OCTET STRING
var signatureLen: uint var signatureLen: uint
if mbedtls_asn1_get_tag( if mbedtls_asn1_get_tag(
addr parsePtr, endPtr, addr signatureLen, MBEDTLS_ASN1_OCTET_STRING addr parsePtr, endPtr, addr signatureLen, MBEDTLS_ASN1_OCTET_STRING
) != 0: ) != 0:
debug "Failed to parse signature OCTET STRING in libp2p extension" debug "Failed to parse signature OCTET STRING in libp2p extension"
return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG return MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
@ -450,9 +452,11 @@ proc libp2pext(
extension[].publicKey = publicKey extension[].publicKey = publicKey
extension[].signature = signature extension[].signature = signature
return 0 # Success return 0 # Success
proc parse*(certificateDer: seq[byte]): P2pCertificate {.raises: [CertificateParsingError].} = proc parse*(
certificateDer: seq[byte]
): P2pCertificate {.raises: [CertificateParsingError].} =
## Parses a DER-encoded certificate and extracts the P2pCertificate. ## Parses a DER-encoded certificate and extracts the P2pCertificate.
## ##
## Parameters: ## Parameters:
@ -475,9 +479,11 @@ proc parse*(certificateDer: seq[byte]): P2pCertificate {.raises: [CertificatePar
certificateDer.len.uint, certificateDer.len.uint,
0, 0,
libp2pext, libp2pext,
addr extension addr extension,
) )
if ret != 0: if ret != 0:
raise newException(CertificateParsingError, "Failed to parse certificate, error code: " & $ret) raise newException(
CertificateParsingError, "Failed to parse certificate, error code: " & $ret
)
return P2pCertificate(certificate: crt, extension: extension) return P2pCertificate(certificate: crt, extension: extension)

View File

@ -5,7 +5,6 @@ import ../../../libp2p/crypto/crypto
import ../../../libp2p/peerid import ../../../libp2p/peerid
suite "Certificate Tests": suite "Certificate Tests":
test "sanity check": test "sanity check":
var rng = newRng() var rng = newRng()