Skip to content

Commit 0c87255

Browse files
committed
Include the SPKI algorithm in log entries
While this makes log entries bigger, the modern tlog-based API compresses runs of 256 entries together, so they should gzip fairly well. Including the algorithm can allow folks to more easily monitor the status of an algorithm transition, and flag some misconfigurations. For example, a PQ-incapable server might ask both a classical and PQ CA to sign its classical key. But a PQ-capable server should ask a classical CA to sign the classical key and a PQ CA to sign its PQ key. Closes #76
1 parent 2026e90 commit 0c87255

2 files changed

Lines changed: 61 additions & 33 deletions

File tree

draft-ietf-plants-merkle-tree-certs.md

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ An issuance log's log ID determines a PKIX distinguished name ({{Section 4.1.2.4
892892
~~~asn.1
893893
id-rdna-trustAnchorID OBJECT IDENTIFIER ::= {
894894
iso(1) identified-organization(3) dod(6) internet(1) security(5)
895-
mechanisms(5) pkix(7) rdna(25) TBD}
895+
mechanisms(5) pkix(7) rdna(25) TBD }
896896
~~~
897897

898898
The attribute's value is a RELATIVE-OID containing the trust anchor ID's ASN.1 representation. For example, the distinguished name for a log named `32473.1` would be represented in syntax of {{?RFC4514}} as:
@@ -934,25 +934,37 @@ struct {
934934
} MerkleTreeCertEntry;
935935
~~~
936936

937+
When `type` is `null_entry`, the entry does not represent any information. The entry at index zero of every issuance log MUST be of type `null_entry`. Other entries MUST NOT use `null_entry`. `null_entry` exists to avoid zero serial numbers in the certificate format ({{certificate-format}}).
938+
937939
When `type` is `tbs_cert_entry`, `N` is the number of bytes needed to consume the rest of the input. A MerkleTreeCertEntry is expected to be decoded in contexts where the total length of the entry is known.
938940

939941
`tbs_cert_entry_data` contains the contents octets (i.e. excluding the initial identifier and length octets) of the DER {{X.690}} encoding of a TBSCertificateLogEntry, defined below. Equivalently, `tbs_cert_entry_data` contains the DER encodings of each field of the TBSCertificateLogEntry, concatenated. This construction allows a single-pass implementation in {{verifying-certificate-signatures}}.
940942

941943
~~~asn.1
942-
TBSCertificateLogEntry ::= SEQUENCE {
943-
version [0] EXPLICIT Version DEFAULT v1,
944-
issuer Name,
945-
validity Validity,
946-
subject Name,
947-
subjectPublicKeyInfoHash OCTET STRING,
948-
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
949-
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
950-
extensions [3] EXPLICIT Extensions{{CertExtensions}} OPTIONAL }
944+
TBSCertificateLogEntry ::= SEQUENCE {
945+
version [0] EXPLICIT Version DEFAULT v1,
946+
issuer Name,
947+
validity Validity,
948+
subject Name,
949+
subjectPublicKeyInfoAlgorithm AlgorithmIdentifier{PUBLIC-KEY,
950+
{PublicKeyAlgorithms}},
951+
subjectPublicKeyInfoHash OCTET STRING,
952+
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
953+
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
954+
extensions [3] EXPLICIT Extensions{{CertExtensions}}
955+
OPTIONAL
956+
}
951957
~~~
952958

953-
The `version`, `issuer`, `validity`, `subject`, `issuerUniqueID`, `subjectUniqueID`, and `extensions` fields have the corresponding semantics as in {{Section 4.1.2 of !RFC5280}}, with the exception of `subjectPublicKeyInfoHash`. `subjectPublicKeyInfoHash` contains the hash of subject's public key as a SubjectPublicKeyInfo ({{Section 4.1.2.7 of !RFC5280}}). The hash uses the log's hash function ({{log-parameters}}) and is computed over the SubjectPublicKeyInfo's DER {{X.690}} encoding. The `issuer` field MUST be the issuance log's log ID as a PKIX distinguished name, as described in {{log-ids}}.
959+
The fields of a TBSCertificateLogEntry are defined as follows:
954960

955-
When `type` is `null_entry`, the entry does not represent any information. The entry at index zero of every issuance log MUST be of type `null_entry`. Other entries MUST NOT use `null_entry`. `null_entry` exists to avoid zero serial numbers in the certificate format ({{certificate-format}}).
961+
* `version`, `issuer`, `validity`, `subject`, `issuerUniqueID`, `subjectUniqueID`, and `extensions` have the same semantics as the corresponding TBSCertificate fields, defined in {{Section 4.1.2 of !RFC5280}}.
962+
963+
* `subjectPublicKeyInfoAlgorithm` describes the algorithm of the subject's public key. It is constructed identically to the `algorithm` field of a SubjectPublicKeyInfo ({{Section 4.1.2.7 of !RFC5280}}).
964+
965+
* `subjectPublicKeyInfoHash` contains the hash of subject's public key, encoded as a SubjectPublicKeyInfo. The hash uses the log's hash function ({{log-parameters}}) and is computed over the SubjectPublicKeyInfo's DER {{X.690}} encoding. The `issuer` field MUST be the issuance log's log ID as a PKIX distinguished name, as described in {{log-ids}}.
966+
967+
Note the subject's public key algorithm is incorporated into both `subjectPublicKeyInfoAlgorithm` and `subjectPublicKeyInfoHash`.
956968

957969
MerkleTreeCertEntry is an extensible structure. Future documents may define new values for MerkleTreeCertEntryType, with corresponding semantics. See {{certification-authority-cosigners}} and {{new-log-entry-types}} for additional discussion.
958970

@@ -1136,14 +1148,14 @@ The TBSCertificate's `version`, `issuer`, `validity`, `subject`, `issuerUniqueID
11361148

11371149
The TBSCertificate's `serialNumber` MUST contain the zero-based index of the TBSCertificateLogEntry in the log. {{Section 4.1.2.2 of !RFC5280}} forbids zero as a serial number, but {{log-entries}} defines a `null_entry` type for use in entry zero, so the index will be positive. This encoding is intended to avoid implementation errors by having the serial numbers and indices off by one.
11381150

1139-
The TBSCertificate's `subjectPublicKeyInfo` contains the specified public key. Its hash MUST match the TBSCertificateLogEntry's `subjectPublicKeyInfoHash`.
1151+
The TBSCertificate's `subjectPublicKeyInfo` contains the specified public key. Its `algorithm` field MUST match the TBSCertificateLogEntry's `subjectPublicKeyAlgorithm`. Its hash MUST match the TBSCertificateLogEntry's `subjectPublicKeyInfoHash`.
11401152

11411153
The TBSCertificate's `signature` and the Certificate's `signatureAlgorithm` MUST contain an AlgorithmIdentifier whose `algorithm` is id-alg-mtcProof, defined below, and whose `parameters` is omitted.
11421154

11431155
~~~asn.1
11441156
id-alg-mtcProof OBJECT IDENTIFIER ::= {
11451157
iso(1) identified-organization(3) dod(6) internet(1) security(5)
1146-
mechanisms(5) pkix(7) algorithms(6) TBD}
1158+
mechanisms(5) pkix(7) algorithms(6) TBD }
11471159
~~~
11481160

11491161
For initial experimentation, early implementations of this design will use the OID 1.3.6.1.4.1.44363.47.0 instead of `id-alg-mtcProof`.
@@ -1290,6 +1302,7 @@ When verifying the signature on an X.509 certificate (Step (a)(1) of {{Section 6
12901302

12911303
1. Construct a TBSCertificateLogEntry as follows:
12921304
1. Copy the `version`, `issuer`, `validity`, `subject`, `issuerUniqueID`, `subjectUniqueID`, and `extensions` fields from the TBSCertificate.
1305+
1. Set `subjectPublicKeyInfoAlgorithm` to the `algorithm` field of the `subjectPublicKeyInfo`.
12931306
1. Set `subjectPublicKeyInfoHash` to the hash of the DER encoding of `subjectPublicKeyInfo`.
12941307

12951308
1. Construct a MerkleTreeCertEntry of type `tbs_cert_entry` with contents the TBSCertificateLogEntry. Let `entry_hash` be the hash of the entry, `MTH({entry}) = HASH(0x00 || entry)`, as defined in {{Section 2.1.1 of !RFC9162}}.
@@ -1307,9 +1320,10 @@ In this procedure, `entry_hash` can equivalently be computed in a single pass fr
13071320
1. Initialize a hash instance.
13081321
1. Write the big-endian, two-byte `tbs_cert_entry` value to the hash.
13091322
1. Write the TBSCertificate contents octets to the hash, up to the `subjectPublicKeyInfo` field.
1323+
1. Write the `subjectPublicKeyInfo`'s `algorithm` field to the hash.
13101324
1. Write the octet 0x04 to the hash. This is an OCTET STRING identifer.
13111325
1. Write the octet L to the hash, where L is the hash length. (This assumes L is at most 127.)
1312-
1. Write H to the hash, where H is the hash of the `subjectPublicKeyInfo` field.
1326+
1. Write H to the hash, where H is the hash of the entire `subjectPublicKeyInfo` field.
13131327
1. Write the remainder of the TBSCertificate contents octets to the hash, starting just after the `subjectPublicKeyInfo` field.
13141328
1. Finalize the hash and set `entry_hash` to the result.
13151329

@@ -1670,8 +1684,8 @@ DEFINITIONS IMPLICIT TAGS ::=
16701684
BEGIN
16711685

16721686
IMPORTS
1673-
SIGNATURE-ALGORITHM
1674-
FROM AlgorithmInformation-2009 -- in [RFC5912]
1687+
SIGNATURE-ALGORITHM, AlgorithmIdentifier{},
1688+
FROM AlgorithmInformation-2009 -- in [RFC5912]
16751689
{ iso(1) identified-organization(3) dod(6) internet(1)
16761690
security(5) mechanisms(5) pkix(7) id-mod(0)
16771691
id-mod-algorithmInformation-02(58) }
@@ -1685,7 +1699,7 @@ IMPORTS
16851699
{ iso(1) identified-organization(3) dod(6) internet(1)
16861700
security(5) mechanisms(5) pkix(7) id-mod(0)
16871701
id-mod-pkix1-implicit-02(59) }
1688-
Version, Name, Validity, UniqueIdentifier
1702+
Version, Name, Validity, UniqueIdentifier, PublicKeyAlgorithms
16891703
FROM PKIX1Explicit-2009 -- in [RFC5912]
16901704
{ iso(1) identified-organization(3) dod(6) internet(1)
16911705
security(5) mechanisms(5) pkix(7) id-mod(0)
@@ -1696,32 +1710,36 @@ IMPORTS
16961710
security(5) mechanisms(5) pkix(7) id-mod(0)
16971711
id-mod-trustAnchorIDs-2025(TBD) } ;
16981712

1699-
TBSCertificateLogEntry ::= SEQUENCE {
1700-
version [0] EXPLICIT Version DEFAULT v1,
1701-
issuer Name,
1702-
validity Validity,
1703-
subject Name,
1704-
subjectPublicKeyInfoHash OCTET STRING,
1705-
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
1706-
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
1707-
extensions [3] EXPLICIT Extensions{{CertExtensions}} OPTIONAL }
1713+
TBSCertificateLogEntry ::= SEQUENCE {
1714+
version [0] EXPLICIT Version DEFAULT v1,
1715+
issuer Name,
1716+
validity Validity,
1717+
subject Name,
1718+
subjectPublicKeyInfoAlgorithm AlgorithmIdentifier{PUBLIC-KEY,
1719+
{PublicKeyAlgorithms}},
1720+
subjectPublicKeyInfoHash OCTET STRING,
1721+
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
1722+
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
1723+
extensions [3] EXPLICIT Extensions{{CertExtensions}}
1724+
OPTIONAL
1725+
}
17081726

17091727
id-alg-mtcProof OBJECT IDENTIFIER ::= {
17101728
iso(1) identified-organization(3) dod(6) internet(1) security(5)
1711-
mechanisms(5) pkix(7) algorithms(6) TBD}
1729+
mechanisms(5) pkix(7) algorithms(6) TBD }
17121730

17131731
sa-mtcProof SIGNATURE-ALGORITHM ::= {
1714-
IDENTIFIER id-alg-mtcProof
1715-
PARAMS ARE absent
1732+
IDENTIFIER id-alg-mtcProof
1733+
PARAMS ARE absent
17161734
}
17171735

17181736
id-rdna-trustAnchorID OBJECT IDENTIFIER ::= {
17191737
iso(1) identified-organization(3) dod(6) internet(1) security(5)
1720-
mechanisms(5) pkix(7) rdna(25) TBD}
1738+
mechanisms(5) pkix(7) rdna(25) TBD }
17211739

17221740
at-trustAnchorID ATTRIBUTE ::= {
1723-
TYPE TrustAnchorID
1724-
IDENTIFIED BY id-rdna-trustAnchorID
1741+
TYPE TrustAnchorID
1742+
IDENTIFIED BY id-rdna-trustAnchorID
17251743
}
17261744

17271745
END
@@ -2141,3 +2159,5 @@ In draft-04, there is no fast issuance mode. In draft-05, frequent, non-landmark
21412159
{:numbered="false"}
21422160

21432161
- Address editorial comments from WG adoption call
2162+
2163+
- Included subject public key algorithm in log entries

estimate_tile_size.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ func tbsCertLogEntryFromCert(cert *x509.Certificate) []byte {
135135
addX509Time(val, cert.NotAfter)
136136
})
137137
tbs.AddBytes(cert.RawSubject)
138+
// Parse out the algorithm.
139+
spki := cryptobyte.String(cert.RawSubjectPublicKeyInfo)
140+
var spkiContents, spkiAlg cryptobyte.String
141+
if !spki.ReadASN1(&spkiContents, cbasn1.SEQUENCE) ||
142+
!spkiContents.ReadASN1Element(&spkiAlg, cbasn1.SEQUENCE) {
143+
panic("could not parse SPKI")
144+
}
145+
tbs.AddBytes(spkiAlg)
138146
hash := sha256.Sum256(cert.RawSubjectPublicKeyInfo)
139147
tbs.AddASN1OctetString(hash[:])
140148
tbs.AddASN1(cbasn1.Tag(3).Constructed().ContextSpecific(), func(exts *cryptobyte.Builder) {

0 commit comments

Comments
 (0)