x509
nimony/lib/std/crypto/x509.nim
X.509 certificates (RFC 5280), as much of them as a TLS client needs to decide whether to believe a server: DER parsing, signature checks, chain building to a trust anchor, validity periods, and host name matching (RFC 6125).
The parser is strict and small. Anything it does not understand that is marked critical makes the certificate unusable, as RFC 5280 requires; anything else is skipped.
type KeyKind = enum kkNone = (0, "kkNone") kkRsa = (1, "kkRsa") kkEcP256 = (2, "kkEcP256") kkEcP384 = (3, "kkEcP384")
func dollar`.KeyKind(e: KeyKind): stringtype PublicKey = object kind: KeyKind rsa: RsaPublicKey ecPoint: seq[uint8]
type SigAlg = enum saUnknown = (0, "saUnknown") saRsaSha256 = (1, "saRsaSha256") saRsaSha384 = (2, "saRsaSha384") saRsaSha512 = (3, "saRsaSha512") saEcdsaSha256 = (4, "saEcdsaSha256") saEcdsaSha384 = (5, "saEcdsaSha384") saEcdsaSha512 = (6, "saEcdsaSha512")
func dollar`.SigAlg(e: SigAlg): stringtype Certificate = object der: seq[uint8] tbsStart: int64 tbsLen: int64 sigAlg: SigAlg signature: seq[uint8] issuer: seq[uint8] subject: seq[uint8] notBefore: int64 notAfter: int64 publicKey: PublicKey isCa: bool pathLen: int64 hasKeyUsage: bool canSignCerts: bool hasEku: bool serverAuth: bool dnsNames: seq[string] ipAddresses: seq[seq[uint8]] commonName: string
type CertError = enum ceNone = (0, "ok") ceParse = (1, "malformed certificate") ceExpired = (2, "certificate expired or not yet valid") ceUntrusted = (3, "no chain to a trusted root") ceBadSignature = (4, "certificate signature does not verify") ceHostMismatch = (5, "certificate is not valid for this host name") ceNotCa = (6, "issuer is not a certificate authority") ceUsage = (7, "certificate may not be used for TLS server authentication") ceChainTooLong = (8, "certificate chain too long")
func dollar`.CertError(e: CertError): stringtype TrustStore = object roots: seq[Certificate] system: bool
func parseCertificate(der: openArray[uint8]; c: var Certificate): boolParses one DER certificate. Checks structure only — nothing here says whether to TRUST it; that is
verifyChain.proc verifyWith(key: PublicKey; alg: SigAlg; message: openArray[uint8]; signature: openArray[uint8]): boolChecks an X.509 signature (PKCS #1 v1.5 for RSA).
proc isSignedBy(c: Certificate; issuer: Certificate): boolfunc matchesHost(c: Certificate; host: string): boolWhether the certificate names
host. Only the subjectAltName counts: the subject's CN has not been a host name for clients since RFC 6125.proc addPem(store: var TrustStore; pem: string): int64Adds every certificate in a PEM bundle; returns how many parsed. Ones that do not parse are skipped: a system bundle may well carry a root with an algorithm this module does not speak.
proc verifyChain(store: TrustStore; chain: openArray[Certificate]; host: string; now: int64): CertErrorchain[0]is the server's certificate, the rest what it sent along to help (in any order, possibly with extras). Builds a path to a root ofstoreand checks validity, CA flags, key usage and the host name.