feat: encode certificates in PEM or DER

This commit is contained in:
Richard Ramos 2025-02-20 16:15:45 -04:00
parent c26ef5fb52
commit d615896924
No known key found for this signature in database
GPG Key ID: 7218C1B2A89A1B6D
2 changed files with 66 additions and 41 deletions

View File

@ -61,6 +61,10 @@ type
certificate*: mbedtls_x509_crt
extension*: P2pExtension
type EncodingFormat* = enum
DER
PEM
proc ptrInc*(p: ptr byte, n: uint): ptr byte =
## Utility function to increment a pointer by n bytes.
cast[ptr byte](cast[uint](p) + n)
@ -84,7 +88,7 @@ proc initializeDRBG() =
mbedtls_entropy_func,
addr entropy,
cast[ptr byte](personalization.cstring),
personalization.len.uint
personalization.len.uint,
)
if ret != 0:
raise newException(KeyGenerationError, "Failed to seed CTR_DRBG")
@ -247,7 +251,7 @@ proc makeLibp2pExtension(
return generateSignedKey(signature, pubKeyBytes)
proc generate*(
identityKeyPair: KeyPair
identityKeyPair: KeyPair, encodingFormat: EncodingFormat = EncodingFormat.DER
): (seq[byte], seq[byte]) {.
raises: [
KeyGenerationError, CertificateCreationError, ASN1EncodingError,
@ -261,8 +265,8 @@ proc generate*(
##
## Returns:
## A tuple containing:
## - The DER-encoded certificate.
## - The DER-encoded private key.
## - The certificate.
## - The private key.
##
## Raises:
## - `KeyGenerationError` if key generation fails.
@ -377,23 +381,22 @@ proc generate*(
# Generate a random serial number
const SERIAL_LEN = 20
var serialBuffer: array[SERIAL_LEN, byte]
ret = mbedtls_ctr_drbg_random(addr ctrDrbg, addr serialBuffer[0], SERIAL_LEN);
ret = mbedtls_ctr_drbg_random(addr ctrDrbg, addr serialBuffer[0], SERIAL_LEN)
if ret != 0:
raise newException(CertificateCreationError, "Failed to generate serial number")
# Set the serial number
ret = mbedtls_x509write_crt_set_serial_raw(addr crt, addr serialBuffer[0], SERIAL_LEN);
ret = mbedtls_x509write_crt_set_serial_raw(addr crt, addr serialBuffer[0], SERIAL_LEN)
if ret != 0:
raise newException(CertificateCreationError, "Failed to set serial number")
# Prepare Buffer for Certificate Serialization
const CERT_BUFFER_SIZE = 4096
var
certBuffer: array[CERT_BUFFER_SIZE, byte]
certLen: cint
var certBuffer: array[CERT_BUFFER_SIZE, byte]
var outputCertificate: seq[byte]
# Write the Certificate in DER Format
certLen = mbedtls_x509write_crt_der(
if encodingFormat == EncodingFormat.DER:
let certLen: cint = mbedtls_x509write_crt_der(
addr crt,
addr certBuffer[0],
CERT_BUFFER_SIZE.uint,
@ -404,30 +407,52 @@ proc generate*(
raise newException(
CertificateCreationError, "Failed to write certificate in DER format"
)
# Adjust the buffer to contain only the DER data
let certificateDer =
# Adjust the buffer to contain only the data
outputCertificate =
toSeq(certBuffer[(CERT_BUFFER_SIZE - certLen) ..< CERT_BUFFER_SIZE])
else:
let ret = mbedtls_x509write_crt_pem(
addr crt,
addr certBuffer[0],
CERT_BUFFER_SIZE.uint,
mbedtls_ctr_drbg_random,
addr ctrDrbg,
)
if ret != 0:
raise newException(
CertificateCreationError, "Failed to write certificate in PEM format"
)
let n = certBuffer.find(0'u8) # Find the index of the first null byte
outputCertificate = certBuffer[0 .. n - 1].toSeq()
# Serialize the Private Key in DER Format (PKCS#8)
var
privKeyBuffer: array[2048, byte]
privKeyLen: cint
# Serialize the Private Key
var privKeyBuffer: array[2048, byte]
var outputPrivateKey: seq[byte]
privKeyLen = mbedtls_pk_write_key_der(
if encodingFormat == EncodingFormat.DER:
let privKeyLen = mbedtls_pk_write_key_der(
addr certKey, addr privKeyBuffer[0], privKeyBuffer.len.uint
)
if privKeyLen < 0:
raise newException(
CertificateCreationError, "Failed to write private key in DER format"
)
# Adjust the buffer to contain only the DER data
let privateKeyDer =
# Adjust the buffer to contain only the data
outputPrivateKey =
toSeq(privKeyBuffer[(privKeyBuffer.len - privKeyLen) ..< privKeyBuffer.len])
else:
let ret = mbedtls_pk_write_key_pem(
addr certKey, addr privKeyBuffer[0], privKeyBuffer.len.uint
)
if ret != 0:
raise newException(
CertificateCreationError, "Failed to write private key in PEM format"
)
let n = privKeyBuffer.find(0'u8) # Find the index of the first null byte
outputPrivateKey = privKeyBuffer[0 .. n - 1].toSeq()
# Return the Serialized Certificate and Private Key
return (certificateDer, privateKeyDer)
return (outputCertificate, outputPrivateKey)
proc libp2pext(
p_ctx: pointer,

View File

@ -12,7 +12,7 @@ suite "Certificate Tests":
let keypair = KeyPair.random(Secp256k1, rng[]).tryGet()
let peerId = PeerId.init(keypair.pubkey).tryGet()
let certBytes = generate(keypair)[0]
let (certBytes, _) = generate(keypair, EncodingFormat.DER)
let cert = parse(certBytes)
let ext = cert.extension