Software Engineering Institute Carnegie Mellon

Into the Black Box: A Case Study in Obtaining Visibility into Commercial Software

3 Certificate Database

The next step was to determine the format of the data and access keys for each database record.

Decoding the certificate database was much easier than expected. We searched the Web and newsgroups using most of the available search engines for information describing Netscape's certificate database. Combinations of the keywords such as cert7.db, decode, ASN.1, DER, certificate-database, format, specification, certificate, security, and Netscape were used as input into the search engines.

It turned out that some information describing the content and format of the Netscape certificate database was available on the Internet. All records in the certificate database have a common header that describes the type of record. This information was described in some detail at the following Web sites (note that one of these sites was overseas, thus calling into question whether export control laws are material insofar as Netscape's product are concerned):

The information at these Web sites did not describe every field of the header or every field of each record. We then obtained a copy of the Netscape Security Services (NSS) library from Netscape. It turned out that Netscape documented, to a certain extent, the exact format of the common header as well as the format for each possible type of record in the database. The common header as shown in Figure 3 has the following fields:

  1. a Version field that indicates the database version (currently 7)
  2. a Type field that indicates the type of record
  3. a Flags field (always zero)



typedef struct 

 {

  unsigned char Version;

  unsigned char Type;

  unsigned char Flags;

 } DBHeader; 


Figure 3: Certificate Database Record Type Header






Using some of the NSS header files, we determined the list of possible record types (the Type field in Figure 3) in the certificate database as shown in Figure 4. Some of this information was also defined in the Internet resources that we located.



// Record Types
 
#define CERT7VERSION        0 
 
#define CERT7CERTIFICATE    1 
 
#define CERT7NICKNAME       2 
 
#define CERT7SUBJECT        3 
 
#define CERT7REVOCATION     4 
 
#define CERT7KEYREVOCATION  5 
 
#define CERT7SMIMEPROFILE   6 
 
#define CERT7CONTENTVERSION 7


Figure 4: Certificate Database Record Types






Then we focused on determining the format of each record. This task was simple thanks to Netscape's NSS header files. Figure 5 shows the C structures that define the format of each record type in the database. These structures were derived using Netscape's header files that document the byte offsets of fields within a record and hexadecimal dumps from the "DBDump" tool described earlier. Records in the certificate database are in big endian format, so all fields that are of the type "unsigned short" must be byte swapped. Most of the important information contained within a record is distinguished encoding rules (DER) encoded.

Two records that are always in the database are the CERT7VERSION and CERT7CONTENTVERSION records. These records have the access key "\0Version\0" and "\7ContentVersion\0" respectively and may be used to identify a certificate database.

Now that we had determined the record formats for the certificate database, a tool to browse the database was constructed. This tool (shown in Figure 6) displays to the user a listing of each record in the database. The user can then select a particular record and the tool will display the key index for the record as well as its contents. Record fields that are DER encoded can be displayed in abstract syntax notation one (ASN.1) or Hex/ASCII format. Additionally, the tool allows the user to save a certificate to a file in DER format.



#define CERTIFICATEHEADERFIXEDSIZE 10 
 
// Flags for Object Signing, E-mail and SSL 
 
#define CERT7DB_VALID_PEER        (1<<0) 
 
#define CERT7DB_TRUSTED           (1<<1) 
 
#define CERT7DB_SEND_WARN         (1<<2) 
 
#define CERT7DB_VALID_CA          (1<<3) 
 
#define CERT7DB_TRUSTED_CA        (1<<4) 
 
#define CERT7DB_NS_TRUSTED_CA     (1<<5) 
 
#define CERT7DB_USER              (1<<6) 
 
#define CERT7DB_TRUSTED_CLIENT_CA (1<<7) 
 
#define CERT7DB_INVISIBLE_CA      (1<<8) 
 
#define CERT7DB_GOVT_APPROVED_CA  (1<<9) 
 
#define CERT7DB_PROTECTED_OS_CA   (1<<10) 
 
typedef struct 
 
 { 
 
    unsigned short SSLFlags; 
 
    unsigned short EMailFlags; 
 
    unsigned short ObjectSigningFlags; 
 
    unsigned short DERCertificateLength; 
 
    unsigned short NickNameLength; 
 
    unsigned char *DERCertificate; 
 
    char          *Nickname; 
 
 }CertificateHeader; 
 
 
#define NICKNAMEHEADERFIXEDSIZE 2 
 
typedef struct 
 
 { 
 
   unsigned short NickNameDERLength; 
 
   unsigned char *NicknameDER; 
 
 }  NickNameHeader; 
 
 
#define SUBJECTHEADERFIXEDSIZE 6 
 
typedef struct 
 
 { 
 
  unsigned short   NumberOfCertificates; 
 
  unsigned short   NicknameLength; 
 
  unsigned short   EmailAddressLength; 
 
  char *           NickName; 
 
  char *           EMailAddress; 
 
  unsigned short * CertificateKeyLength; 
 
  unsigned short * KeyIDLength; 
 
  unsigned char  * CertificateKeys; 
 
  unsigned char  * KeyIDs; 
 
 }SubjectHeader; 
 
 
#define MIMEHEADERFIXEDSIZE 6 
 
typedef struct 
 
{ 
 
  unsigned short  DERSubjectNameLength; 
 
  unsigned short  MineOptionsLength; 
 
  unsigned short  OptionsDateLen; 
 
  unsigned char * DERSubjectName; 
 
  unsigned char * MimeOptions; 
 
  unsigned char * OptionsDate; 
 
} MimeHeader; 
 
 
 
#define REVOCATIONHEADERFIXEDSIZE 4 
 
typedef struct 
 
{ 
 
 unsigned short  DERCertificateLength; 
 
 unsigned short  URLLength; 
 
 unsigned char  *DERCertificate; 
 
 char           *URL; 
 
} RevocationHeader; 
 
 
#define CERTVERSIONHEADERFIXEDSIZE  0 
 
typedef struct 
 
{ 
 
 // Contains just the common header 
 
} CertVersionHeader; 
 
#define  CERTCONTENTVERSIONHEADERFIXEDSIZE 1 
 
typedef struct 
 
{ 
 
 unsigned char ContentVersion; 
 
} CertContentVersionHeader; 


Figure 5: Certificate Database Record Formats






The database key information shown in Figure 6 at the beginning of the record content is used by the database to quickly retrieve a record. A record is typically retrieved using the key information as shown in the code fragment below:


DBT key, data; 
 
 
key.data=(void *)"Version"; 
 
 
key.size=strlen("Version")+1; 
 
 
if ((db->get)(db,&key,&data,0)==RET_SUCCESS) DisplayRecord(&data);
In the above example the key and data variable are the type DBT (data base thang [sic]) as described in the Berkley 1.85 documentation.

The exact details of how Netscape selects keys for each particular type of record are unknown. In some cases the database key appears to contain DER encoded information while in other cases the key appears to be just a string. Additional information regarding database index keys will be discussed in the next section.

Figure 6: Database Browsing Tool

[abstract] [chapter 1] [chapter 2] [chapter 3] [chapter 4] [chapter 5] [references] [DTIC] [PDF]