Physical Format of pcertdb
Newsgroup:
mozilla.dev.tech.crypto
There are currently seven record types stored in the permanent cert database.
RowID
Usually one uses "keys" to find records in a database. However, since
we have various encryption keys floating around, and in fact an entire
"key database," I use the term "RowID" here to refer to the things used
to specify records in databases.
All rowIDs begin with a single byte, whose value indicates the record
type.
Payloads
All payloads begin with a three-byte header. The first byte indicates
the database format version. The second byte indicates the record
type, and should match the record type byte of the corresponding rowID.
The third byte consists of flags
[flag info to come].
Specific record types
Database version
RowID
The rowID of this database record is a fixed null-terminated ascii string,
"Version."
Payload
The only point of this record is to store the database format version,
which is stored as the first byte of all payloads. Therefore, this
payload only includes the common header.
Certificate
RowID
RowIDs are the guaranteed unique combination of the certificate issuer's
(DER-encoded) distinguished name, and that serial number of the cert as
assigned by that issuer. The issuer's DN is provided in DER-encoded
format in the certificate
[description
of DER encoding of DNs to come], and the serial number is DER-encoded as
an integer. To make a rowID, the DN is not decoded, though the integer
serial number is.
1 |
DER-encoded issuer |
integer serial number |
Payload
The first three elements of this record after the common header are each
two-byte sets of flags, indicating for what purposes this cert is "trusted."
The first set of flags is for SSL, the second is for S/MIME e-mail, and
the third is for object signing. Then comes a two-byte integer (most
significant byte first) indicating the length in bytes of the DER-encoded
certificate. Then comes a two-byte integer indicating the length
of the certificate's nickname; this nickname length may be zero, in which
case no nickname is present. Then comes the DER-encoded certificate
itself, and finally any nickname as a null-terminated ascii string.
7 |
1 |
f |
ssl |
email |
os |
length of DER-encoded cert |
length of nickname or zero |
DER-encoded cert |
nickname (optional) |
The trust bits are defined by or'ing together the following values:
0x0001 |
Valid peer |
0x0002 |
Trusted |
0x0004 |
Warn before posting over ssl connections with
this server cert |
0x0008 |
Valid CA cert |
0x0010 |
CA cert trusted for issuing server certs |
0x0020 |
NS trusted CA [means
what?] |
0x0040 |
User certificate |
0x0080 |
CA cert trusted for issuing client certs |
0x0100 |
"Invisible" cert -- don't show in UI (was
used for policy-file cert) |
0x0200 |
"Government approved" -- can do strong crypto
in export clients |
0x0400 |
May do object signing, even if not marked
for object signing [is this set on disk? or
just memory?] |
0x0800 |
(unused) |
0x1000 |
(unused) |
0x2000 |
(unused) |
0x4000 |
(unused) |
0x8000 |
(unused) |
Version six of this entry only had one byte for each of the ssl, email,
and object signing flags; with only the eight least significant bits defined.
Nickname
Nickname entries map ascii strings to cert subjects, which are described
below.
RowID
The rowID is just a null-terminated ascii string.
2 |
Nickname as an ascii string |
\0 |
Payload
The payload contains a two-byte integer (most significant byte first) specifying
the length of the following DER-encoded cert subject, followed by the DER-encoded
subject itself.
7 |
2 |
f |
Length of DER-encoded cert subject |
DER-encoded cert subject |
Subject
Subject entries map cert subjects (distinguished names) to the certs themselves
(well, the cert's rowIDs, which are composed of their issuer and serial
number) and to the
[keyIDs].
RowID
The rowID is just the DER-encoded subject of the cert, which is a distinguished
name.
3 |
DER-encoded distinguished name |
Payload
The payloads of these records are complex. The first thing after the
common header is a two-byte integer specifying how many cert rowIDs and
keyIDs are listed in this entry. That integer, like all others in
this record, is most-significant-byte first. After that comes another
two-byte integer, specifying the length of the nickname for this subject.
The nickname is presented as a null-terminated ascii string. If there
is no nickname, the string consists of merely the null terminating byte,
and hence the minimum nickname length is one. After that comes another
two-byte integer, this one specifying the length of the email address corresponding
to this subject. It, too, is a null-terminated ascii string with
a minimum length of one. After these lengths comes the null-terminated
nickname, and after that, the null-terminated e-mail address.
Next, there are N two-byte integers, each one specifying the length
of a cert rowID. After that, there are N more two-byte integers,
each one specifying the length of a keyID. Finally, there are the
N cert rowIDs, and the N keyIDs.
7 |
3 |
f |
# of certs N |
nickname length |
email length |
ascii nickname |
\0 |
email address |
\0 |
len of cert 0 rowID |
len of cert 1 rowID |
(...) |
len of cert (N-1) rowID |
len of keyID 0 |
len of keyID 1 |
(...) |
len of keyID (N-1) |
cert 0 rowID |
cert 1 rowID |
(...) |
cert (N-1) rowID |
keyID 0 |
keyID 1 |
(...) |
keyID (N-1) |
CRL
RowID
The rowID for CRLs is the DER-encoded distinguished name of the cert server
issuing the CRL.
4 |
DER-encoded DN of the issuing cert server |
Payload
The first part of this record after the common header is a two-byte integer
indicating the length of the DER-encoded CRL itself. Next, there
is a two-byte integer indicating the length of the "nickname" URL associated
with the CRL
[more info describing the purpose of
the url to come]. The URL is a null-terminated ascii string.
If there is no URL, merely the null termination is present. Therefore,
the minimum URL length is 1. Next comes the DER-encoded CRL, then
the URL as a null-terminated ASCII string.
7 |
4 |
f |
length of DER-encoded CRL |
length of URL |
DER-encoded CRL [more
info to come] |
URL [more info to come] |
\0 |
KRL
RowID
There can only be one key revocation list (KRL) in a database, so its rowID consists merely of
the record type. (KRLs are used with FORTEZZA only.)
Payload
The first part of this record after the common header is a two-byte integer
indicating the length of the DER-encoded KRL itself. Next, there
is a two-byte integer indicating the length of the "nickname" URL associated
with the KRL
[more info describing the purpose of
the url to come]. The URL is a null-terminated ascii string.
If there is no URL, merely the null termination is present. Therefore,
the minimum URL length is 1. Next comes the DER-encoded KRL, then
the URL as a null-terminated ASCII string.
7 |
5 |
f |
length of DER-encoded KRL |
length of URL |
DER-encoded KRL [more
info to come] |
URL [more info to come] |
\0 |
S/MIME profile
RowID
The rowID for an S/MIME profile is a null-terminated ascii string containing
the e-mail address for which this profile applies.
[Info
to come on what formats are valid for the e-mail address]
Payload
After the common header, there are three two-byte integers indicating the
lengths of (respectively), the subject name field, the options field, and
the options date field. Following those lengths come the subject
name, which is the DER-encoded distinguished name associated with this
e-mail address; the S/MIME options, which is the value of the PKCS#7 attribute
tagged by SEC_OID_PKCS9_SMIME_CAPABILITIES
[format
details to come]; and the timestamp of those options, inUTCTime format.
The timestamp is usually the signing time of the message from which these
capabilities are taken.
7 |
6 |
f |
length of subject name |
length of S/MIME options |
length of options timestamp |
DER-encoded distinguished
name associated with this e-mail address |
S/MIME options |
options timestamp, in UTCTime
format. |
Content Version
RowID
The rowID of this database record is the fixed null-terminated ascii string,
"ContentVersion."
7 |
C |
o |
n |
t |
e |
n |
t |
V |
e |
r |
s |
i |
o |
n |
\0 |
Payload
After the common header, there is a one-byte integer, with the version
number of the database contents. This number is revised when the
permanent data compiled into the security library changes, so that the
initialization code knows what changes to make to the permanent database
to bring it into line with the compiled-in data.