Browse the docs

silk.tls.certificate.

Decode one X.509 certificate from DER or PEM, and read its fields.

When to use#

Use Certificate.decodePem for a .pem or .crt file with one CERTIFICATE block, and Certificate.decodeDer for binary DER, such as a certificate from a TLS handshake. For a file with more than one certificate, use silk.tls.certificate_bundle.

Details#

A Certificate owns a copy of its DER bytes. The accessors return slices of that DER, such as Certificate.subjectDer or Certificate.tbsDer, and decoded values, such as Certificate.notAfter. Nothing is normalized: names, algorithms, and extensions keep their original bytes, and unknown or duplicate extensions stay available. DecodeLimits bound the work for input that you do not control.

Errors#

  • DecodeError if the input is not a valid certificate or goes over a limit. reason gives the rule, and offset with offsetSpace gives the position.

  • OutOfMemoryError if the Allocator fails.

Gotchas#

Decoding checks only the structure. It does not verify the signature, the chain, the names, or the dates. Use silk.tls.certificate_path for that. The PEM decoder is strict: text outside the block, other labels, and non-canonical Base64 are errors.

Examples#

Report where a PEM certificate is broken#

silk
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.tls.certificate { Certificate, DecodeError, DecodeLimits, DecodeReason }
import silk.core.effect { Effect }
import silk.core.result { Result }

pub effect fn main() -> i32
  ! OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let pem = b"-----BEGIN CERTIFICATE-----\n!!!!\n-----END CERTIFICATE-----\n"
  let decoded = run Certificate.decodePem(pem, DecodeLimits.defaults())
    |> Effect.provideMut<Allocator>(&mut allocator)
  return match move decoded {
    Result<Certificate, DecodeError>.Failure { error } => {
      // `!` is not a Base64 character.
      if error.reason != DecodeReason.Base64 {
        return 1
      }
      return 0
    }
    Result<Certificate, DecodeError>.Success { value: _ } => 1
  }
}

Import as Certificate with import silk.tls.certificate { Certificate }.

Public declarations: 12.

DecodeLimits#

silk
pub struct DecodeLimits

The resource limits for one decode call. Each limit is inclusive, and 0 allows nothing. DecodeLimits.defaults gives safe values.

Field inputBytes#

silk
pub inputBytes: usize

The maximum input length, with PEM whitespace.

Field certificateBytes#

silk
pub certificateBytes: usize

The maximum DER length of one certificate.

Field totalDerBytes#

silk
pub totalDerBytes: usize

The maximum DER length of all certificates together.

Field certificates#

silk
pub certificates: usize

The maximum number of certificates, with duplicates.

Field fieldBytes#

silk
pub fieldBytes: usize

The maximum content length of one field.

Field extensions#

silk
pub extensions: usize

The maximum number of extensions in one certificate.

Field depth#

silk
pub depth: usize

The maximum nesting depth of DER values. The certificate itself has depth 1.

Field nodes#

silk
pub nodes: usize

The maximum number of DER values in one certificate.

Implementation Copy for DecodeLimits#

silk
impl Copy for DecodeLimits

Implementation DecodeLimits#

silk
impl DecodeLimits

Associated function defaults#

silk
pub fn defaults() -> DecodeLimits

Returns the default limits: 16 MiB of input, 1 MiB for each certificate, 8 MiB of DER in total, 1024 certificates, 256 KiB for each field, 256 extensions, a depth of 32, and 65536 DER values for each certificate.

DecodeClass#

silk
pub enum DecodeClass

The kind of a DecodeError.

Malformed#

silk
Malformed

The input breaks a rule of PEM, DER, or the X.509 structure.

Unsupported#

silk
Unsupported

The input is valid, but its version or PEM label is not supported.

ResourceLimit#

silk
ResourceLimit

The input goes over a DecodeLimits value or a size that the target can hold.

Implementation Debug for DecodeClass#

silk
impl Debug for DecodeClass

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as Malformed.

DecodeReason#

silk
pub enum DecodeReason

The rule that a DecodeError broke.

EmptyInput#

silk
EmptyInput

The input has no certificate.

PemSyntax#

silk
PemSyntax

A PEM marker or a byte between the markers is not valid.

Base64#

silk
Base64

The Base64 has a character, padding, or unused bits that are not valid.

TrailingData#

silk
TrailingData

There are bytes after the one certificate that the function reads.

Truncated#

silk
Truncated

The input ends before a value is complete.

Tag#

silk
Tag

A DER tag is not valid.

Length#

silk
Length

A DER length is not in its shortest form.

Integer#

silk
Integer

An INTEGER is empty or not in its shortest form.

Boolean#

silk
Boolean

A BOOLEAN is not one byte of 0x00 or 0xff.

BitString#

silk
BitString

The unused-bit count of a BIT STRING, or its unused bits, are not valid.

Oid#

silk
Oid

An object identifier is not valid.

SetOrder#

silk
SetOrder

The values of a SET OF in a name are not in DER order.

DefaultValue#

silk
DefaultValue

A field that has its default value is encoded. DER does not allow it.

Time#

silk
Time

A time or date is not valid.

Schema#

silk
Schema

The fields do not have the structure of an X.509 certificate.

StringEncoding#

silk
StringEncoding

A text field does not follow its string type.

Version#

silk
Version

The version is not v1, v2, or v3.

PemLabel#

silk
PemLabel

The PEM label is not CERTIFICATE.

InputBytes#

silk
InputBytes

The input is longer than inputBytes.

CertificateBytes#

silk
CertificateBytes

A certificate is longer than certificateBytes.

TotalDerBytes#

silk
TotalDerBytes

All certificates together are longer than totalDerBytes.

Certificates#

silk
Certificates

There are more certificates than certificates.

FieldBytes#

silk
FieldBytes

A field is longer than fieldBytes.

Extensions#

silk
Extensions

A certificate has more extensions than extensions.

Depth#

silk
Depth

The DER values nest deeper than depth.

Nodes#

silk
Nodes

A certificate has more DER values than nodes.

SizeOverflow#

silk
SizeOverflow

A length, a tag number, or an allocation size does not fit in usize.

Implementation Debug for DecodeReason#

silk
impl Debug for DecodeReason

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as EmptyInput.

DecodeOffsetSpace#

silk
pub enum DecodeOffsetSpace

The bytes that DecodeError.offset counts in.

Input#

silk
Input

The offset is a position in the input that you gave.

Der#

silk
Der

The offset is a position in the DER of the PEM block at certificateIndex, after Base64 decoding.

Implementation Debug for DecodeOffsetSpace#

silk
impl Debug for DecodeOffsetSpace

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the variant, such as Input.

CertificateVersion#

silk
pub enum CertificateVersion

The X.509 version of a certificate.

V1#

silk
V1

Version 1. The version field is absent.

V2#

silk
V2

Version 2.

V3#

silk
V3

Version 3. Most certificates use it, because only v3 has extensions.

DecodeError#

silk
pub struct DecodeError

A certificate decoding error, with the rule and the position. It does not borrow the input.

Details#

reason gives the rule that the input broke. offset gives the position, and offsetSpace tells if offset counts in the input or in the decoded DER.

Field kind#

silk
pub kind: DecodeClass

The kind of error.

Field reason#

silk
pub reason: DecodeReason

The rule that the input broke.

Field certificateIndex#

silk
pub certificateIndex: usize

The index of the certificate that failed, from 0. Errors in the document itself use 0.

Field offsetSpace#

silk
pub offsetSpace: DecodeOffsetSpace

Tells you if offset counts in the input or in the decoded DER.

Field offset#

silk
pub offset: usize

The position of the byte or tag that failed, or the position where missing data must be.

Implementation Copy for DecodeError#

silk
impl Copy for DecodeError

Implementation Debug for DecodeError#

silk
impl Debug for DecodeError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the fields, as DecodeError { kind: ..., reason: ..., ... }.

CertificateTime#

silk
pub struct CertificateTime

A date and time in UTC from a certificate.

Field year#

silk
pub year: u16

The year, from 1 to 9999.

Field month#

silk
pub month: u8

The month, from 1 to 12.

Field day#

silk
pub day: u8

The day of the month.

Field hour#

silk
pub hour: u8

The hour, from 0 to 23.

Field minute#

silk
pub minute: u8

The minute, from 0 to 59.

Field second#

silk
pub second: u8

The second, from 0 to 59.

Implementation Copy for CertificateTime#

silk
impl Copy for CertificateTime

BitStringView#

silk
pub struct BitStringView<'a>

The content of a BIT STRING, such as a public key or a signature. It borrows the certificate.

Field bytes#

silk
pub bytes: &'a [u8]

The bits, without the first byte that counts the unused bits.

Field unusedBits#

silk
pub unusedBits: u8

The number of unused bits at the end of the last byte. Keys and signatures use 0.

AlgorithmView#

silk
pub struct AlgorithmView<'a>

An algorithm identifier, such as the signature algorithm. It borrows the certificate.

Field der#

silk
pub der: &'a [u8]

The full DER of the AlgorithmIdentifier.

Field oid#

silk
pub oid: &'a [u8]

The bytes of the object identifier, without the tag and the length.

Field parametersDer#

silk
pub parametersDer: Option<&'a [u8]>

The full DER of the parameters, or None if they are absent. Absent parameters and an explicit NULL are different.

CertificateOffsets#

silk
pub struct CertificateOffsets

The positions of the main fields in the DER of a certificate. Use them to point at a field in an error message.

Field tbs#

silk
pub tbs: usize

The position of the TBSCertificate, the part that the issuer signs.

Field version#

silk
pub version: usize

The position of the version field, or the first TBSCertificate field if the version is absent.

Field serial#

silk
pub serial: usize

The position of the serial number.

Field tbsSignatureAlgorithm#

silk
pub tbsSignatureAlgorithm: usize

The position of the signature algorithm inside the TBSCertificate.

Field issuer#

silk
pub issuer: usize

The position of the issuer name.

Field subject#

silk
pub subject: usize

The position of the subject name.

Field spki#

silk
pub spki: usize

The position of the SubjectPublicKeyInfo.

Field publicKey#

silk
pub publicKey: usize

The position of the public key BIT STRING.

Field signatureAlgorithm#

silk
pub signatureAlgorithm: usize

The position of the outer signature algorithm.

Field signature#

silk
pub signature: usize

The position of the signature BIT STRING.

Field issuerUniqueId#

silk
pub issuerUniqueId: usize

The position of the issuer unique ID, or the TBSCertificate if it is absent.

Field subjectUniqueId#

silk
pub subjectUniqueId: usize

The position of the subject unique ID, or the TBSCertificate if it is absent.

ExtensionView#

silk
pub struct ExtensionView<'a>

One extension of a certificate, as it is in the DER. It borrows the certificate.

Field offset#

silk
pub offset: usize

The position of the extension in the DER of the certificate.

Field valueOffset#

silk
pub valueOffset: usize

The position of the extension value in the DER of the certificate.

Field der#

silk
pub der: &'a [u8]

The full DER of the extension.

Field oid#

silk
pub oid: &'a [u8]

The bytes of the extension object identifier, without the tag and the length.

Field critical#

silk
pub critical: bool

true if the extension is marked critical. An absent flag is false.

Field value#

silk
pub value: &'a [u8]

The bytes inside the extension OCTET STRING. They are not decoded.

Certificate#

silk
pub struct Certificate

A decoded X.509 certificate that owns its DER bytes.

When to use#

Make one with Certificate.decodePem for a .pem or .crt file with one CERTIFICATE block, or with Certificate.decodeDer for binary DER, such as a certificate from a TLS handshake. For a file with more than one certificate, use silk.tls.certificate_bundle.

Details#

The accessors return slices of the DER, such as Certificate.subjectDer, and decoded values, such as Certificate.notAfter. Nothing is normalized: names, algorithms, and extensions keep their original bytes. The accessors borrow the certificate. Unknown algorithms, duplicate extensions, and other values that a validator can reject stay available, so that silk.tls.certificate_profile can check them.

Gotchas#

Decoding checks only the structure. It does not verify the signature, the chain, the names, or the dates. Use silk.tls.certificate_path for that.

Implementation Certificate#

silk
impl Certificate

Method copy#

silk
pub effect fn copy(self: &Self) -> Certificate ! OutOfMemoryError ? &mut Allocator

Returns a copy of the certificate. It does not decode again.

Errors#

  • OutOfMemoryError if the Allocator fails.

Associated function decodeDer#

silk
pub effect fn decodeDer(input: &[u8], limits: DecodeLimits) -> Result<Certificate, DecodeError>
  ! OutOfMemoryError
  ? &mut Allocator

Decodes one DER certificate from input, and copies it.

All of input must be the certificate. Bytes after it, also whitespace, are an error. The limits in limits bound the work for input that you do not control.

Errors#

  • Failure with a DecodeError if input is not one valid certificate or goes over a limit.

  • OutOfMemoryError if the Allocator fails.

Gotchas#

Decoding checks only the structure. It does not verify the signature, the chain, the names, or the dates. Use silk.tls.certificate_path for that.

Associated function decodePem#

silk
pub effect fn decodePem(input: &[u8], limits: DecodeLimits) -> Result<Certificate, DecodeError>
  ! OutOfMemoryError
  ? &mut Allocator

Decodes one PEM CERTIFICATE block from input.

Spaces, tabs, CR, and LF are allowed around the Base64 lines. The Base64 must be canonical.

Errors#

  • Failure with a DecodeError if there is text outside the block, a second block, another label, or a certificate that is not valid.

  • OutOfMemoryError if the Allocator fails.

Gotchas#

Some PEM readers ignore text outside the block. This one does not. Use CertificateBundle.decodeAnnotatedPem for a CA file with comments.

Decoding checks only the structure. It does not verify the signature, the chain, the names, or the dates. Use silk.tls.certificate_path for that.

Method tbsDer#

silk
pub fn tbsDer(self: &Self) -> &[u8]

Returns the DER of the TBSCertificate, the part that the issuer signs.

Method issuerDer#

silk
pub fn issuerDer(self: &Self) -> &[u8]

Returns the DER of the issuer name, as it is. It is not normalized.

Method subjectDer#

silk
pub fn subjectDer(self: &Self) -> &[u8]

Returns the DER of the subject name, as it is. It is not normalized.

Method validityDer#

silk
pub fn validityDer(self: &Self) -> &[u8]

Returns the DER of the validity period.

Method spkiDer#

silk
pub fn spkiDer(self: &Self) -> &[u8]

Returns the DER of the SubjectPublicKeyInfo: the key algorithm and the public key.

Method der#

silk
pub fn der(self: &Self) -> &[u8]

Returns the full DER of the certificate.

Method version#

silk
pub fn version(self: &Self) -> CertificateVersion

Returns the X.509 version.

Method offsets#

silk
pub fn offsets(self: &Self) -> CertificateOffsets

Returns the positions of the main fields in Certificate.der.

Method serial#

silk
pub fn serial(self: &Self) -> &[u8]

Returns the bytes of the serial number, as a big-endian signed integer. A leading zero byte is kept when the high bit is set.

Method notBefore#

silk
pub fn notBefore(self: &Self) -> CertificateTime

Returns the start of the validity period. It does not read a clock.

Method notAfter#

silk
pub fn notAfter(self: &Self) -> CertificateTime

Returns the end of the validity period. It does not check that it is after Certificate.notBefore.

Method publicKey#

silk
pub fn publicKey<'a>(self: &'a Self) -> BitStringView<'a>

Returns the subject public key bits.

Method signature#

silk
pub fn signature<'a>(self: &'a Self) -> BitStringView<'a>

Returns the signature bits.

Method publicKeyAlgorithm#

silk
pub fn publicKeyAlgorithm<'a>(self: &'a Self) -> AlgorithmView<'a>

Returns the algorithm of the subject public key.

Method tbsSignatureAlgorithm#

silk
pub fn tbsSignatureAlgorithm<'a>(self: &'a Self) -> AlgorithmView<'a>

Returns the signature algorithm inside the TBSCertificate. It must be the same as Certificate.signatureAlgorithm, but this function does not check it.

Method signatureAlgorithm#

silk
pub fn signatureAlgorithm<'a>(self: &'a Self) -> AlgorithmView<'a>

Returns the outer signature algorithm, which the issuer used to sign.

Method issuerUniqueId#

silk
pub fn issuerUniqueId<'a>(self: &'a Self) -> Option<BitStringView<'a>>

Returns the issuer unique ID, or None if it is absent. Modern certificates do not use it.

Method subjectUniqueId#

silk
pub fn subjectUniqueId<'a>(self: &'a Self) -> Option<BitStringView<'a>>

Returns the subject unique ID, or None if it is absent. Modern certificates do not use it.

Method extensionCount#

silk
pub fn extensionCount(self: &Self) -> usize

Returns the number of extensions, with unknown and duplicate ones.

Method extension#

silk
pub fn extension<'a>(self: &'a Self, index: usize) -> Option<ExtensionView<'a>>

Returns the extension at index in source order, or None if index is out of range. The value is not decoded.

Category: TLS and certificates.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.

View the source of this page