diff options
60 files changed, 6580 insertions, 47 deletions
diff --git a/Makefile.am b/Makefile.am index 7ab4468..44608c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,15 @@ +if WITH_TRUST_MODULE +TRUST_DIR = trust +else +TRUST_DIR = +endif + SUBDIRS = \ build \ common \ p11-kit \ + $(TRUST_DIR) \ tools \ doc \ po diff --git a/build/Makefile.am b/build/Makefile.am index f8841ec..de76c58 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -1,4 +1,6 @@ +SUBDIRS = certs + EXTRA_DIST = \ cutest \ Makefile.tests diff --git a/build/certs/Makefile.am b/build/certs/Makefile.am new file mode 100644 index 0000000..03dca0d --- /dev/null +++ b/build/certs/Makefile.am @@ -0,0 +1,27 @@ + +# Note that nothing here is distributed. It just lives in the git repository +# We copy everything into its final location, and those test files are +# distributed in the tarballs + +TRUST = $(top_srcdir)/trust/tests + +prepare-certs: + cp -v cacert3.der $(TRUST)/anchors + cp -v cacert3.der $(TRUST)/files + cp -v cacert-ca.der $(TRUST)/certificates + cp -v cacert-ca.der $(TRUST)/files + cp -v self-server.der $(TRUST)/files + cp -v self-signed-with-eku.der $(TRUST)/certificates + cp -v self-signed-with-ku.der $(TRUST)/certificates + cp -v testing-ca.der $(TRUST)/anchors + cp -v testing-server.der $(TRUST)/files + +# Rebuild the self-signed certificates. This is almost never necessary and +# will require other changes in the code, mostly here as documentation +build-self-signed: + openssl req -new -x509 -outform DER -out self-signed-with-eku.der \ + -newkey rsa -keyout /dev/null -nodes -subj /CN=self-signed-with-eku.example.com \ + -config with-eku.conf -set_serial 888 -extensions v3_ca + openssl req -new -x509 -outform DER -out self-signed-with-ku.der \ + -newkey rsa -keyout /dev/null -nodes -subj /CN=self-signed-with-ku.example.com \ + -config with-ku.conf -set_serial 888 -extensions v3_ca diff --git a/build/certs/cacert-ca.der b/build/certs/cacert-ca.der Binary files differnew file mode 100644 index 0000000..719b0ff --- /dev/null +++ b/build/certs/cacert-ca.der diff --git a/build/certs/cacert3.der b/build/certs/cacert3.der Binary files differnew file mode 100644 index 0000000..56f8c88 --- /dev/null +++ b/build/certs/cacert3.der diff --git a/build/certs/self-server.der b/build/certs/self-server.der Binary files differnew file mode 100644 index 0000000..68fe9af --- /dev/null +++ b/build/certs/self-server.der diff --git a/build/certs/self-signed-with-eku.der b/build/certs/self-signed-with-eku.der Binary files differnew file mode 100644 index 0000000..33e0760 --- /dev/null +++ b/build/certs/self-signed-with-eku.der diff --git a/build/certs/self-signed-with-ku.der b/build/certs/self-signed-with-ku.der Binary files differnew file mode 100644 index 0000000..e6f36e3 --- /dev/null +++ b/build/certs/self-signed-with-ku.der diff --git a/build/certs/testing-ca.der b/build/certs/testing-ca.der Binary files differnew file mode 100644 index 0000000..d3f70ea --- /dev/null +++ b/build/certs/testing-ca.der diff --git a/build/certs/testing-server.der b/build/certs/testing-server.der Binary files differnew file mode 100644 index 0000000..cf2de65 --- /dev/null +++ b/build/certs/testing-server.der diff --git a/build/certs/with-eku.conf b/build/certs/with-eku.conf new file mode 100644 index 0000000..8eab21d --- /dev/null +++ b/build/certs/with-eku.conf @@ -0,0 +1,19 @@ +# +# Use with the following command +# $ openssl req -new -x509 -outform DER -out self-signed-with-ku.pem \ +# -newkey rsa -keyout self-signed-with-ku.key -nodes \ +# -config with-ku.conf -set_serial 888 -extensions v3_ca +# + +[ req ] +default_bits = 1024 +distinguished_name = req_distinguished_name +x509_extensions = v3_ca +dirstring_type = nobmp + +[ req_distinguished_name ] +commonName = Common Name +commonName_max = 64 + +[ v3_ca ] +keyUsage=keyCertSign,digitalSignature
\ No newline at end of file diff --git a/build/certs/with-ku.conf b/build/certs/with-ku.conf new file mode 100644 index 0000000..aa0acc1 --- /dev/null +++ b/build/certs/with-ku.conf @@ -0,0 +1,19 @@ +# +# Use with the following command +# $ openssl req -new -x509 -outform DER -out self-signed-with-eku.pem \ +# -newkey rsa -keyout self-signed-with-eku.key -nodes \ +# -config with-eku.conf -set_serial 888 -extensions v3_ca +# + +[ req ] +default_bits = 1024 +distinguished_name = req_distinguished_name +x509_extensions = v3_ca +dirstring_type = nobmp + +[ req_distinguished_name ] +commonName = Common Name +commonName_max = 64 + +[ v3_ca ] +extendedKeyUsage=clientAuth,emailProtection,1.2.3.4
\ No newline at end of file diff --git a/common/Makefile.am b/common/Makefile.am index aae9b35..5f2852e 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -26,17 +26,24 @@ libp11_library_la_SOURCES = \ dict.c dict.h \ library.c library.h \ pkcs11.h pkcs11x.h \ - pkix.asn pkix.asn.h \ $(NULL) +libp11_mock_la_SOURCES = \ + mock.c mock.h \ + $(NULL) + +if WITH_ASN1 + noinst_LTLIBRARIES += \ libp11-data.la \ $(NULL) libp11_data_la_SOURCES = \ checksum.c checksum.h \ + pkix.asn pkix.asn.h \ $(NULL) -libp11_mock_la_SOURCES = \ - mock.c mock.h \ - $(NULL) +asn: + asn1Parser -o pkix.asn.h pkix.asn + +endif # WITH_ASN1 diff --git a/common/compat.c b/common/compat.c index a22071a..74fb130 100644 --- a/common/compat.c +++ b/common/compat.c @@ -37,6 +37,7 @@ #include "compat.h" #include <assert.h> +#include <errno.h> #include <stdlib.h> #include <string.h> @@ -185,6 +186,72 @@ p11_thread_join (p11_thread_t thread) #endif /* OS_WIN32 */ +#ifndef HAVE_STRNSTR + +/*- + * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org> + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <string.h> + +/* + * Find the first occurrence of find in s, where the search is limited to the + * first slen characters of s. + */ +char * +strnstr (const char *s, + const char *find, + size_t slen) +{ + char c, sc; + size_t len; + + if ((c = *find++) != '\0') { + len = strlen (find); + do { + do { + if (slen-- < 1 || (sc = *s++) == '\0') + return (NULL); + } while (sc != c); + if (len > slen) + return (NULL); + } while (strncmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} + +#endif /* HAVE_STRNSTR */ + #ifndef HAVE_MEMDUP void * @@ -204,3 +271,43 @@ memdup (void *data, } #endif /* HAVE_MEMDUP */ + +#ifndef HAVE_STRCONCAT + +#include <stdarg.h> + +char * +strconcat (const char *first, + ...) +{ + size_t length = 0; + const char *arg; + char *result, *at; + va_list va; + + va_start (va, first); + + for (arg = first; arg; arg = va_arg (va, const char*)) + length += strlen (arg); + + va_end (va); + + at = result = malloc (length + 1); + if (result == NULL) + return NULL; + + va_start (va, first); + + for (arg = first; arg; arg = va_arg (va, const char*)) { + length = strlen (arg); + memcpy (at, arg, length); + at += length; + } + + va_end (va); + + *at = 0; + return result; +} + +#endif /* HAVE_STRCONCAT */ diff --git a/common/compat.h b/common/compat.h index 6305768..68786a7 100644 --- a/common/compat.h +++ b/common/compat.h @@ -39,8 +39,6 @@ #include <sys/types.h> -typedef enum { false, true } bool; - #if !defined(__cplusplus) && (__GNUC__ > 2) #define GNUC_PRINTF(x, y) __attribute__((__format__(__printf__, x, y))) #else @@ -175,6 +173,14 @@ typedef void * dl_module_t; #include <errno.h> #endif /* HAVE_ERRNO_H */ +#ifndef HAVE_STRNSTR + +char * strnstr (const char *s, + const char *find, + size_t slen); + +#endif /* HAVE_STRNSTR */ + #ifndef HAVE_MEMDUP void * memdup (void *data, @@ -188,4 +194,11 @@ void * memdup (void *data, typedef enum { false, true } bool; #endif +#ifndef HAVE_STRCONCAT + +char * strconcat (const char *first, + ...) GNUC_NULL_TERMINATED; + +#endif /* HAVE_STRCONCAT */ + #endif /* __COMPAT_H__ */ diff --git a/common/debug.c b/common/debug.c index 2728bf6..1ef51d3 100644 --- a/common/debug.c +++ b/common/debug.c @@ -55,6 +55,7 @@ static struct DebugKey debug_keys[] = { { "conf", P11_DEBUG_CONF }, { "uri", P11_DEBUG_URI }, { "proxy", P11_DEBUG_PROXY }, + { "trust", P11_DEBUG_TRUST }, { 0, } }; diff --git a/common/debug.h b/common/debug.h index 2374b6f..ff2af0f 100644 --- a/common/debug.h +++ b/common/debug.h @@ -43,6 +43,7 @@ enum { P11_DEBUG_CONF = 1 << 2, P11_DEBUG_URI = 1 << 3, P11_DEBUG_PROXY = 1 << 4, + P11_DEBUG_TRUST = 1 << 5, }; extern int p11_debug_current_flags; @@ -83,6 +84,16 @@ void p11_debug_precond (const char *format, return v; \ } while (false) +#define warn_if_reached(v) \ + do { \ + p11_debug_precond ("p11-kit: shouldn't be reached at %s\n", __func__); \ + } while (false) + +#define warn_if_fail(x) \ + do { if (!(x)) { \ + p11_debug_precond ("p11-kit: '%s' not true at %s\n", #x, __func__); \ + } } while (false) + #endif /* DEBUG_H */ /* ----------------------------------------------------------------------------- diff --git a/common/pkix.asn b/common/pkix.asn new file mode 100644 index 0000000..38bb028 --- /dev/null +++ b/common/pkix.asn @@ -0,0 +1,566 @@ + +PKIX1 { } + +DEFINITIONS IMPLICIT TAGS ::= + +BEGIN + +-- This contains both PKIX1Implicit88 and RFC2630 ASN.1 modules. + +id-pkix OBJECT IDENTIFIER ::= + { iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) } + +-- ISO arc for standard certificate and CRL extensions + +-- authority key identifier OID and syntax + +AuthorityKeyIdentifier ::= SEQUENCE { + keyIdentifier [0] KeyIdentifier OPTIONAL, + authorityCertIssuer [1] GeneralNames OPTIONAL, + authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + -- authorityCertIssuer and authorityCertSerialNumber shall both + -- be present or both be absgent + +KeyIdentifier ::= OCTET STRING + +-- subject key identifier OID and syntax + +SubjectKeyIdentifier ::= KeyIdentifier + +-- key usage extension OID and syntax + +KeyUsage ::= BIT STRING + +-- Directory string type -- + +DirectoryString ::= CHOICE { + teletexString TeletexString (SIZE (1..MAX)), + printableString PrintableString (SIZE (1..MAX)), + universalString UniversalString (SIZE (1..MAX)), + utf8String UTF8String (SIZE (1..MAX)), + bmpString BMPString (SIZE(1..MAX)), + -- IA5String is added here to handle old UID encoded as ia5String -- + -- See tests/userid/ for more information. It shouldn't be here, -- + -- so if it causes problems, considering dropping it. -- + ia5String IA5String (SIZE(1..MAX)) } + +SubjectAltName ::= GeneralNames + +GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + +GeneralName ::= CHOICE { + otherName [0] AnotherName, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ANY, +-- Changed to work with the libtasn1 parser. + directoryName [4] EXPLICIT RDNSequence, --Name, + ediPartyName [5] ANY, --EDIPartyName replaced by ANY to save memory + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } + +-- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as +-- TYPE-IDENTIFIER is not supported in the '88 ASN.1 syntax + +AnotherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER, + value [0] EXPLICIT ANY DEFINED BY type-id } + +-- issuer alternative name extension OID and syntax + +IssuerAltName ::= GeneralNames + +-- basic constraints extension OID and syntax + +BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..MAX) OPTIONAL } + +-- CRL distribution points extension OID and syntax + +CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + +DistributionPoint ::= SEQUENCE { + distributionPoint [0] EXPLICIT DistributionPointName OPTIONAL, + reasons [1] ReasonFlags OPTIONAL, + cRLIssuer [2] GeneralNames OPTIONAL +} + +DistributionPointName ::= CHOICE { + fullName [0] GeneralNames, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName +} + +ReasonFlags ::= BIT STRING + +-- extended key usage extension OID and syntax + +ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + +KeyPurposeId ::= OBJECT IDENTIFIER + +-- CRL number extension OID and syntax + +CRLNumber ::= INTEGER (0..MAX) + +-- certificate issuer CRL entry extension OID and syntax + +CertificateIssuer ::= GeneralNames + +-- -------------------------------------- +-- EXPLICIT +-- -------------------------------------- + +-- UNIVERSAL Types defined in '93 and '98 ASN.1 +-- but required by this specification + +NumericString ::= [UNIVERSAL 18] IMPLICIT OCTET STRING + +IA5String ::= [UNIVERSAL 22] IMPLICIT OCTET STRING + +TeletexString ::= [UNIVERSAL 20] IMPLICIT OCTET STRING + +PrintableString ::= [UNIVERSAL 19] IMPLICIT OCTET STRING + +UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING + -- UniversalString is defined in ASN.1:1993 + +BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING + -- BMPString is the subtype of UniversalString and models + -- the Basic Multilingual Plane of ISO/IEC/ITU 10646-1 + +UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING + -- The content of this type conforms to RFC 2279. + + +-- attribute data types -- + +Attribute ::= SEQUENCE { + type AttributeType, + values SET OF AttributeValue + -- at least one value is required -- +} + +AttributeType ::= OBJECT IDENTIFIER + +AttributeValue ::= ANY DEFINED BY type + +AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value AttributeValue } + +-- suggested naming attributes: Definition of the following +-- information object set may be augmented to meet local +-- requirements. Note that deleting members of the set may +-- prevent interoperability with conforming implementations. +-- presented in pairs: the AttributeType followed by the +-- type definition for the corresponding AttributeValue + +-- Arc for standard naming attributes +id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} + +-- Attributes of type NameDirectoryString + +-- gnutls: Note that the Object ID (id-at*) is being set just before the +-- actual definition. This is done in order for asn1_find_structure_from_oid +-- to work (locate structure from OID). +-- Maybe this is inefficient and memory consuming. Should we replace with +-- a table that maps OIDs to structures? + +PostalAddress ::= SEQUENCE OF DirectoryString + + -- Legacy attributes + +emailAddress AttributeType ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 1 } + +Pkcs9email ::= IA5String (SIZE (1..ub-emailaddress-length)) + +-- naming data types -- + +Name ::= CHOICE { -- only one possibility for now -- + rdnSequence RDNSequence } + +RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +DistinguishedName ::= RDNSequence + +RelativeDistinguishedName ::= + SET SIZE (1 .. MAX) OF AttributeTypeAndValue + + + +-- -------------------------------------------------------- +-- certificate and CRL specific structures begin here +-- -------------------------------------------------------- + +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING } + +TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version shall be v2 or v3 + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version shall be v2 or v3 + extensions [3] EXPLICIT Extensions OPTIONAL + -- If present, version shall be v3 -- +} + +Version ::= INTEGER { v1(0), v2(1), v3(2) } + +CertificateSerialNumber ::= INTEGER + +Validity ::= SEQUENCE { + notBefore Time, + notAfter Time } + +Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + +UniqueIdentifier ::= BIT STRING + +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING } + +Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING } + + +-- ------------------------------------------ +-- CRL structures +-- ------------------------------------------ + +CertificateList ::= SEQUENCE { + tbsCertList TBSCertList, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING } + +TBSCertList ::= SEQUENCE { + version Version OPTIONAL, + -- if present, shall be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, shall be v2 + } OPTIONAL, + crlExtensions [0] EXPLICIT Extensions OPTIONAL + -- if present, shall be v2 -- +} + +-- Version, Time, CertificateSerialNumber, and Extensions were +-- defined earlier for use in the certificate structure + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + -- contains a value of the type + -- registered for use with the + -- algorithm object identifier value + +-- Algorithm OIDs and parameter structures + +Dss-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} + +DomainParameters ::= SEQUENCE { + p INTEGER, -- odd prime, p=jq +1 + g INTEGER, -- generator, g + q INTEGER, -- factor of p-1 + j INTEGER OPTIONAL, -- subgroup factor, j>= 2 + validationParms ValidationParms OPTIONAL } + +ValidationParms ::= SEQUENCE { + seed BIT STRING, + pgenCounter INTEGER } + +Dss-Parms ::= SEQUENCE { + p INTEGER, + q INTEGER, + g INTEGER } + +-- x400 address syntax starts here +-- OR Names + +CountryName ::= [APPLICATION 1] CHOICE { + x121-dcc-code NumericString + (SIZE (ub-country-name-numeric-length)), + iso-3166-alpha2-code PrintableString + (SIZE (ub-country-name-alpha-length)) } + +OrganizationName ::= PrintableString + (SIZE (1..ub-organization-name-length)) +-- see also teletex-organization-name + +NumericUserIdentifier ::= NumericString + (SIZE (1..ub-numeric-user-id-length)) + +-- see also teletex-personal-name + +OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units) + OF OrganizationalUnitName +-- see also teletex-organizational-unit-names + +OrganizationalUnitName ::= PrintableString (SIZE + (1..ub-organizational-unit-name-length)) + +-- Extension types and attribute values +-- + +CommonName ::= PrintableString + +-- END of PKIX1Implicit88 + + +-- BEGIN of RFC2630 + +-- Cryptographic Message Syntax + +pkcs-7-ContentInfo ::= SEQUENCE { + contentType pkcs-7-ContentType, + content [0] EXPLICIT ANY DEFINED BY contentType } + +pkcs-7-DigestInfo ::= SEQUENCE { + digestAlgorithm pkcs-7-DigestAlgorithmIdentifier, + digest pkcs-7-Digest +} + +pkcs-7-Digest ::= OCTET STRING + +pkcs-7-ContentType ::= OBJECT IDENTIFIER + +pkcs-7-SignedData ::= SEQUENCE { + version pkcs-7-CMSVersion, + digestAlgorithms pkcs-7-DigestAlgorithmIdentifiers, + encapContentInfo pkcs-7-EncapsulatedContentInfo, + certificates [0] IMPLICIT pkcs-7-CertificateSet OPTIONAL, + crls [1] IMPLICIT pkcs-7-CertificateRevocationLists OPTIONAL, + signerInfos pkcs-7-SignerInfos +} + +pkcs-7-CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4) } + +pkcs-7-DigestAlgorithmIdentifiers ::= SET OF pkcs-7-DigestAlgorithmIdentifier + +pkcs-7-DigestAlgorithmIdentifier ::= AlgorithmIdentifier + +pkcs-7-EncapsulatedContentInfo ::= SEQUENCE { + eContentType pkcs-7-ContentType, + eContent [0] EXPLICIT OCTET STRING OPTIONAL } + +-- We don't use CertificateList here since we only want +-- to read the raw data. +pkcs-7-CertificateRevocationLists ::= SET OF ANY + +pkcs-7-CertificateChoices ::= CHOICE { +-- Although the paper uses Certificate type, we +-- don't use it since, we don't need to parse it. +-- We only need to read and store it. + certificate ANY +} + +pkcs-7-CertificateSet ::= SET OF pkcs-7-CertificateChoices + +pkcs-7-SignerInfos ::= SET OF ANY -- this is not correct but we don't use it + -- anyway + + +-- BEGIN of RFC2986 + +-- Certificate requests +pkcs-10-CertificationRequestInfo ::= SEQUENCE { + version INTEGER { v1(0) }, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] Attributes +} + +Attributes ::= SET OF Attribute + +pkcs-10-CertificationRequest ::= SEQUENCE { + certificationRequestInfo pkcs-10-CertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +-- stuff from PKCS#9 + +pkcs-9-at-challengePassword OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 7} + +pkcs-9-challengePassword ::= CHOICE { + printableString PrintableString, + utf8String UTF8String } + +pkcs-9-localKeyId ::= OCTET STRING + +-- PKCS #8 stuff + +-- Private-key information syntax + +pkcs-8-PrivateKeyInfo ::= SEQUENCE { + version pkcs-8-Version, + privateKeyAlgorithm AlgorithmIdentifier, + privateKey pkcs-8-PrivateKey, + attributes [0] Attributes OPTIONAL } + +pkcs-8-Version ::= INTEGER {v1(0)} + +pkcs-8-PrivateKey ::= OCTET STRING + +pkcs-8-Attributes ::= SET OF Attribute + +-- Encrypted private-key information syntax + +pkcs-8-EncryptedPrivateKeyInfo ::= SEQUENCE { + encryptionAlgorithm AlgorithmIdentifier, + encryptedData pkcs-8-EncryptedData +} + +pkcs-8-EncryptedData ::= OCTET STRING + +-- PKCS #5 stuff + +pkcs-5-des-EDE3-CBC-params ::= OCTET STRING (SIZE(8)) +pkcs-5-aes128-CBC-params ::= OCTET STRING (SIZE(16)) +pkcs-5-aes192-CBC-params ::= OCTET STRING (SIZE(16)) +pkcs-5-aes256-CBC-params ::= OCTET STRING (SIZE(16)) + +pkcs-5-PBES2-params ::= SEQUENCE { + keyDerivationFunc AlgorithmIdentifier, + encryptionScheme AlgorithmIdentifier } + +-- PBKDF2 + +-- pkcs-5-algid-hmacWithSHA1 AlgorithmIdentifier ::= +-- {algorithm pkcs-5-id-hmacWithSHA1, parameters NULL : NULL} + +pkcs-5-PBKDF2-params ::= SEQUENCE { + salt CHOICE { + specified OCTET STRING, + otherSource AlgorithmIdentifier + }, + iterationCount INTEGER (1..MAX), + keyLength INTEGER (1..MAX) OPTIONAL, + prf AlgorithmIdentifier OPTIONAL -- DEFAULT pkcs-5-id-hmacWithSHA1 +} + +-- PKCS #12 stuff + +pkcs-12-PFX ::= SEQUENCE { + version INTEGER {v3(3)}, + authSafe pkcs-7-ContentInfo, + macData pkcs-12-MacData OPTIONAL +} + +pkcs-12-PbeParams ::= SEQUENCE { + salt OCTET STRING, + iterations INTEGER +} + +pkcs-12-MacData ::= SEQUENCE { + mac pkcs-7-DigestInfo, + macSalt OCTET STRING, + iterations INTEGER DEFAULT 1 +-- Note: The default is for historical reasons and its use is +-- deprecated. A higher value, like 1024 is recommended. +} + +pkcs-12-AuthenticatedSafe ::= SEQUENCE OF pkcs-7-ContentInfo + -- Data if unencrypted + -- EncryptedData if password-encrypted + -- EnvelopedData if public key-encrypted + +pkcs-12-SafeContents ::= SEQUENCE OF pkcs-12-SafeBag + +pkcs-12-SafeBag ::= SEQUENCE { + bagId OBJECT IDENTIFIER, + bagValue [0] EXPLICIT ANY DEFINED BY badId, + bagAttributes SET OF pkcs-12-PKCS12Attribute OPTIONAL +} + +-- Bag types + +pkcs-12-KeyBag ::= pkcs-8-PrivateKeyInfo + +-- Shrouded KeyBag + +pkcs-12-PKCS8ShroudedKeyBag ::= pkcs-8-EncryptedPrivateKeyInfo + +-- CertBag + +pkcs-12-CertBag ::= SEQUENCE { + certId OBJECT IDENTIFIER, + certValue [0] EXPLICIT ANY DEFINED BY certId +} + +-- x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {pkcs-9-certTypes 1}} +-- DER-encoded X.509 certificate stored in OCTET STRING + +pkcs-12-CRLBag ::= SEQUENCE { + crlId OBJECT IDENTIFIER, + crlValue [0] EXPLICIT ANY DEFINED BY crlId +} + +pkcs-12-SecretBag ::= SEQUENCE { + secretTypeId OBJECT IDENTIFIER, + secretValue [0] EXPLICIT ANY DEFINED BY secretTypeId +} + +-- x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {pkcs-9-crlTypes 1}} +-- DER-encoded X.509 CRL stored in OCTET STRING + +pkcs-12-PKCS12Attribute ::= Attribute + +-- PKCS #7 stuff (needed in PKCS 12) + +pkcs-7-Data ::= OCTET STRING + +pkcs-7-EncryptedData ::= SEQUENCE { + version pkcs-7-CMSVersion, + encryptedContentInfo pkcs-7-EncryptedContentInfo, + unprotectedAttrs [1] IMPLICIT pkcs-7-UnprotectedAttributes OPTIONAL } + +pkcs-7-EncryptedContentInfo ::= SEQUENCE { + contentType pkcs-7-ContentType, + contentEncryptionAlgorithm pkcs-7-ContentEncryptionAlgorithmIdentifier, + encryptedContent [0] IMPLICIT pkcs-7-EncryptedContent OPTIONAL } + +pkcs-7-ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + +pkcs-7-EncryptedContent ::= OCTET STRING + +pkcs-7-UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute + +-- rfc3820 + +ProxyCertInfo ::= SEQUENCE { + pCPathLenConstraint INTEGER (0..MAX) OPTIONAL, + proxyPolicy ProxyPolicy } + +ProxyPolicy ::= SEQUENCE { + policyLanguage OBJECT IDENTIFIER, + policy OCTET STRING OPTIONAL } + +END diff --git a/common/pkix.asn.h b/common/pkix.asn.h new file mode 100644 index 0000000..d5d5cc4 --- /dev/null +++ b/common/pkix.asn.h @@ -0,0 +1,408 @@ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <libtasn1.h> + +const ASN1_ARRAY_TYPE pkix_asn1_tab[] = { + { "PKIX1", 536875024, NULL }, + { NULL, 1073741836, NULL }, + { "id-pkix", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "identified-organization", 1073741825, "3"}, + { "dod", 1073741825, "6"}, + { "internet", 1073741825, "1"}, + { "security", 1073741825, "5"}, + { "mechanisms", 1073741825, "5"}, + { "pkix", 1, "7"}, + { "AuthorityKeyIdentifier", 1610612741, NULL }, + { "keyIdentifier", 1610637314, "KeyIdentifier"}, + { NULL, 4104, "0"}, + { "authorityCertIssuer", 1610637314, "GeneralNames"}, + { NULL, 4104, "1"}, + { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, + { NULL, 4104, "2"}, + { "KeyIdentifier", 1073741831, NULL }, + { "SubjectKeyIdentifier", 1073741826, "KeyIdentifier"}, + { "KeyUsage", 1073741830, NULL }, + { "DirectoryString", 1610612754, NULL }, + { "teletexString", 1612709890, "TeletexString"}, + { "MAX", 524298, "1"}, + { "printableString", 1612709890, "PrintableString"}, + { "MAX", 524298, "1"}, + { "universalString", 1612709890, "UniversalString"}, + { "MAX", 524298, "1"}, + { "utf8String", 1612709890, "UTF8String"}, + { "MAX", 524298, "1"}, + { "bmpString", 1612709890, "BMPString"}, + { "MAX", 524298, "1"}, + { "ia5String", 538968066, "IA5String"}, + { "MAX", 524298, "1"}, + { "SubjectAltName", 1073741826, "GeneralNames"}, + { "GeneralNames", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "GeneralName"}, + { "GeneralName", 1610612754, NULL }, + { "otherName", 1610620930, "AnotherName"}, + { NULL, 4104, "0"}, + { "rfc822Name", 1610620930, "IA5String"}, + { NULL, 4104, "1"}, + { "dNSName", 1610620930, "IA5String"}, + { NULL, 4104, "2"}, + { "x400Address", 1610620941, NULL }, + { NULL, 4104, "3"}, + { "directoryName", 1610620930, "RDNSequence"}, + { NULL, 2056, "4"}, + { "ediPartyName", 1610620941, NULL }, + { NULL, 4104, "5"}, + { "uniformResourceIdentifier", 1610620930, "IA5String"}, + { NULL, 4104, "6"}, + { "iPAddress", 1610620935, NULL }, + { NULL, 4104, "7"}, + { "registeredID", 536879116, NULL }, + { NULL, 4104, "8"}, + { "AnotherName", 1610612741, NULL }, + { "type-id", 1073741836, NULL }, + { "value", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "type-id", 1, NULL }, + { "IssuerAltName", 1073741826, "GeneralNames"}, + { "BasicConstraints", 1610612741, NULL }, + { "cA", 1610645508, NULL }, + { NULL, 131081, NULL }, + { "pathLenConstraint", 537411587, NULL }, + { "0", 10, "MAX"}, + { "CRLDistributionPoints", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "DistributionPoint"}, + { "DistributionPoint", 1610612741, NULL }, + { "distributionPoint", 1610637314, "DistributionPointName"}, + { NULL, 2056, "0"}, + { "reasons", 1610637314, "ReasonFlags"}, + { NULL, 4104, "1"}, + { "cRLIssuer", 536895490, "GeneralNames"}, + { NULL, 4104, "2"}, + { "DistributionPointName", 1610612754, NULL }, + { "fullName", 1610620930, "GeneralNames"}, + { NULL, 4104, "0"}, + { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"}, + { NULL, 4104, "1"}, + { "ReasonFlags", 1073741830, NULL }, + { "ExtKeyUsageSyntax", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "KeyPurposeId"}, + { "KeyPurposeId", 1073741836, NULL }, + { "CRLNumber", 1611137027, NULL }, + { "0", 10, "MAX"}, + { "CertificateIssuer", 1073741826, "GeneralNames"}, + { "NumericString", 1610620935, NULL }, + { NULL, 4360, "18"}, + { "IA5String", 1610620935, NULL }, + { NULL, 4360, "22"}, + { "TeletexString", 1610620935, NULL }, + { NULL, 4360, "20"}, + { "PrintableString", 1610620935, NULL }, + { NULL, 4360, "19"}, + { "UniversalString", 1610620935, NULL }, + { NULL, 4360, "28"}, + { "BMPString", 1610620935, NULL }, + { NULL, 4360, "30"}, + { "UTF8String", 1610620935, NULL }, + { NULL, 4360, "12"}, + { "Attribute", 1610612741, NULL }, + { "type", 1073741826, "AttributeType"}, + { "values", 536870927, NULL }, + { NULL, 2, "AttributeValue"}, + { "AttributeType", 1073741836, NULL }, + { "AttributeValue", 1614807053, NULL }, + { "type", 1, NULL }, + { "AttributeTypeAndValue", 1610612741, NULL }, + { "type", 1073741826, "AttributeType"}, + { "value", 2, "AttributeValue"}, + { "id-at", 1879048204, NULL }, + { "joint-iso-ccitt", 1073741825, "2"}, + { "ds", 1073741825, "5"}, + { NULL, 1, "4"}, + { "PostalAddress", 1610612747, NULL }, + { NULL, 2, "DirectoryString"}, + { "emailAddress", 1880096780, "AttributeType"}, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "rsadsi", 1073741825, "113549"}, + { "pkcs", 1073741825, "1"}, + { NULL, 1073741825, "9"}, + { NULL, 1, "1"}, + { "Pkcs9email", 1612709890, "IA5String"}, + { "ub-emailaddress-length", 524298, "1"}, + { "Name", 1610612754, NULL }, + { "rdnSequence", 2, "RDNSequence"}, + { "RDNSequence", 1610612747, NULL }, + { NULL, 2, "RelativeDistinguishedName"}, + { "DistinguishedName", 1073741826, "RDNSequence"}, + { "RelativeDistinguishedName", 1612709903, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "AttributeTypeAndValue"}, + { "Certificate", 1610612741, NULL }, + { "tbsCertificate", 1073741826, "TBSCertificate"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "TBSCertificate", 1610612741, NULL }, + { "version", 1610653698, "Version"}, + { NULL, 1073741833, "v1"}, + { NULL, 2056, "0"}, + { "serialNumber", 1073741826, "CertificateSerialNumber"}, + { "signature", 1073741826, "AlgorithmIdentifier"}, + { "issuer", 1073741826, "Name"}, + { "validity", 1073741826, "Validity"}, + { "subject", 1073741826, "Name"}, + { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, + { "issuerUniqueID", 1610637314, "UniqueIdentifier"}, + { NULL, 4104, "1"}, + { "subjectUniqueID", 1610637314, "UniqueIdentifier"}, + { NULL, 4104, "2"}, + { "extensions", 536895490, "Extensions"}, + { NULL, 2056, "3"}, + { "Version", 1610874883, NULL }, + { "v1", 1073741825, "0"}, + { "v2", 1073741825, "1"}, + { "v3", 1, "2"}, + { "CertificateSerialNumber", 1073741827, NULL }, + { "Validity", 1610612741, NULL }, + { "notBefore", 1073741826, "Time"}, + { "notAfter", 2, "Time"}, + { "Time", 1610612754, NULL }, + { "utcTime", 1090519057, NULL }, + { "generalTime", 8388625, NULL }, + { "UniqueIdentifier", 1073741830, NULL }, + { "SubjectPublicKeyInfo", 1610612741, NULL }, + { "algorithm", 1073741826, "AlgorithmIdentifier"}, + { "subjectPublicKey", 6, NULL }, + { "Extensions", 1612709899, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "Extension"}, + { "Extension", 1610612741, NULL }, + { "extnID", 1073741836, NULL }, + { "critical", 1610645508, NULL }, + { NULL, 131081, NULL }, + { "extnValue", 7, NULL }, + { "CertificateList", 1610612741, NULL }, + { "tbsCertList", 1073741826, "TBSCertList"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "TBSCertList", 1610612741, NULL }, + { "version", 1073758210, "Version"}, + { "signature", 1073741826, "AlgorithmIdentifier"}, + { "issuer", 1073741826, "Name"}, + { "thisUpdate", 1073741826, "Time"}, + { "nextUpdate", 1073758210, "Time"}, + { "revokedCertificates", 1610629131, NULL }, + { NULL, 536870917, NULL }, + { "userCertificate", 1073741826, "CertificateSerialNumber"}, + { "revocationDate", 1073741826, "Time"}, + { "crlEntryExtensions", 16386, "Extensions"}, + { "crlExtensions", 536895490, "Extensions"}, + { NULL, 2056, "0"}, + { "AlgorithmIdentifier", 1610612741, NULL }, + { "algorithm", 1073741836, NULL }, + { "parameters", 541081613, NULL }, + { "algorithm", 1, NULL }, + { "Dss-Sig-Value", 1610612741, NULL }, + { "r", 1073741827, NULL }, + { "s", 3, NULL }, + { "DomainParameters", 1610612741, NULL }, + { "p", 1073741827, NULL }, + { "g", 1073741827, NULL }, + { "q", 1073741827, NULL }, + { "j", 1073758211, NULL }, + { "validationParms", 16386, "ValidationParms"}, + { "ValidationParms", 1610612741, NULL }, + { "seed", 1073741830, NULL }, + { "pgenCounter", 3, NULL }, + { "Dss-Parms", 1610612741, NULL }, + { "p", 1073741827, NULL }, + { "q", 1073741827, NULL }, + { "g", 3, NULL }, + { "CountryName", 1610620946, NULL }, + { NULL, 1073746952, "1"}, + { "x121-dcc-code", 1612709890, "NumericString"}, + { NULL, 1048586, "ub-country-name-numeric-length"}, + { "iso-3166-alpha2-code", 538968066, "PrintableString"}, + { NULL, 1048586, "ub-country-name-alpha-length"}, + { "OrganizationName", 1612709890, "PrintableString"}, + { "ub-organization-name-length", 524298, "1"}, + { "NumericUserIdentifier", 1612709890, "NumericString"}, + { "ub-numeric-user-id-length", 524298, "1"}, + { "OrganizationalUnitNames", 1612709899, NULL }, + { "ub-organizational-units", 1074266122, "1"}, + { NULL, 2, "OrganizationalUnitName"}, + { "OrganizationalUnitName", 1612709890, "PrintableString"}, + { "ub-organizational-unit-name-length", 524298, "1"}, + { "CommonName", 1073741826, "PrintableString"}, + { "pkcs-7-ContentInfo", 1610612741, NULL }, + { "contentType", 1073741826, "pkcs-7-ContentType"}, + { "content", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "contentType", 1, NULL }, + { "pkcs-7-DigestInfo", 1610612741, NULL }, + { "digestAlgorithm", 1073741826, "pkcs-7-DigestAlgorithmIdentifier"}, + { "digest", 2, "pkcs-7-Digest"}, + { "pkcs-7-Digest", 1073741831, NULL }, + { "pkcs-7-ContentType", 1073741836, NULL }, + { "pkcs-7-SignedData", 1610612741, NULL }, + { "version", 1073741826, "pkcs-7-CMSVersion"}, + { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"}, + { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"}, + { "certificates", 1610637314, "pkcs-7-CertificateSet"}, + { NULL, 4104, "0"}, + { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"}, + { NULL, 4104, "1"}, + { "signerInfos", 2, "pkcs-7-SignerInfos"}, + { "pkcs-7-CMSVersion", 1610874883, NULL }, + { "v0", 1073741825, "0"}, + { "v1", 1073741825, "1"}, + { "v2", 1073741825, "2"}, + { "v3", 1073741825, "3"}, + { "v4", 1, "4"}, + { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL }, + { NULL, 2, "pkcs-7-DigestAlgorithmIdentifier"}, + { "pkcs-7-DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, + { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL }, + { "eContentType", 1073741826, "pkcs-7-ContentType"}, + { "eContent", 536895495, NULL }, + { NULL, 2056, "0"}, + { "pkcs-7-CertificateRevocationLists", 1610612751, NULL }, + { NULL, 13, NULL }, + { "pkcs-7-CertificateChoices", 1610612754, NULL }, + { "certificate", 13, NULL }, + { "pkcs-7-CertificateSet", 1610612751, NULL }, + { NULL, 2, "pkcs-7-CertificateChoices"}, + { "pkcs-7-SignerInfos", 1610612751, NULL }, + { NULL, 13, NULL }, + { "pkcs-10-CertificationRequestInfo", 1610612741, NULL }, + { "version", 1610874883, NULL }, + { "v1", 1, "0"}, + { "subject", 1073741826, "Name"}, + { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"}, + { "attributes", 536879106, "Attributes"}, + { NULL, 4104, "0"}, + { "Attributes", 1610612751, NULL }, + { NULL, 2, "Attribute"}, + { "pkcs-10-CertificationRequest", 1610612741, NULL }, + { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"}, + { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "signature", 6, NULL }, + { "pkcs-9-at-challengePassword", 1879048204, NULL }, + { "iso", 1073741825, "1"}, + { "member-body", 1073741825, "2"}, + { "us", 1073741825, "840"}, + { "rsadsi", 1073741825, "113549"}, + { "pkcs", 1073741825, "1"}, + { NULL, 1073741825, "9"}, + { NULL, 1, "7"}, + { "pkcs-9-challengePassword", 1610612754, NULL }, + { "printableString", 1073741826, "PrintableString"}, + { "utf8String", 2, "UTF8String"}, + { "pkcs-9-localKeyId", 1073741831, NULL }, + { "pkcs-8-PrivateKeyInfo", 1610612741, NULL }, + { "version", 1073741826, "pkcs-8-Version"}, + { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "privateKey", 1073741826, "pkcs-8-PrivateKey"}, + { "attributes", 536895490, "Attributes"}, + { NULL, 4104, "0"}, + { "pkcs-8-Version", 1610874883, NULL }, + { "v1", 1, "0"}, + { "pkcs-8-PrivateKey", 1073741831, NULL }, + { "pkcs-8-Attributes", 1610612751, NULL }, + { NULL, 2, "Attribute"}, + { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL }, + { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"}, + { "encryptedData", 2, "pkcs-8-EncryptedData"}, + { "pkcs-8-EncryptedData", 1073741831, NULL }, + { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "8"}, + { "pkcs-5-aes128-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "16"}, + { "pkcs-5-aes192-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "16"}, + { "pkcs-5-aes256-CBC-params", 1612709895, NULL }, + { NULL, 1048586, "16"}, + { "pkcs-5-PBES2-params", 1610612741, NULL }, + { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"}, + { "encryptionScheme", 2, "AlgorithmIdentifier"}, + { "pkcs-5-PBKDF2-params", 1610612741, NULL }, + { "salt", 1610612754, NULL }, + { "specified", 1073741831, NULL }, + { "otherSource", 2, "AlgorithmIdentifier"}, + { "iterationCount", 1611137027, NULL }, + { "1", 10, "MAX"}, + { "keyLength", 1611153411, NULL }, + { "1", 10, "MAX"}, + { "prf", 16386, "AlgorithmIdentifier"}, + { "pkcs-12-PFX", 1610612741, NULL }, + { "version", 1610874883, NULL }, + { "v3", 1, "3"}, + { "authSafe", 1073741826, "pkcs-7-ContentInfo"}, + { "macData", 16386, "pkcs-12-MacData"}, + { "pkcs-12-PbeParams", 1610612741, NULL }, + { "salt", 1073741831, NULL }, + { "iterations", 3, NULL }, + { "pkcs-12-MacData", 1610612741, NULL }, + { "mac", 1073741826, "pkcs-7-DigestInfo"}, + { "macSalt", 1073741831, NULL }, + { "iterations", 536903683, NULL }, + { NULL, 9, "1"}, + { "pkcs-12-AuthenticatedSafe", 1610612747, NULL }, + { NULL, 2, "pkcs-7-ContentInfo"}, + { "pkcs-12-SafeContents", 1610612747, NULL }, + { NULL, 2, "pkcs-12-SafeBag"}, + { "pkcs-12-SafeBag", 1610612741, NULL }, + { "bagId", 1073741836, NULL }, + { "bagValue", 1614815245, NULL }, + { NULL, 1073743880, "0"}, + { "badId", 1, NULL }, + { "bagAttributes", 536887311, NULL }, + { NULL, 2, "pkcs-12-PKCS12Attribute"}, + { "pkcs-12-KeyBag", 1073741826, "pkcs-8-PrivateKeyInfo"}, + { "pkcs-12-PKCS8ShroudedKeyBag", 1073741826, "pkcs-8-EncryptedPrivateKeyInfo"}, + { "pkcs-12-CertBag", 1610612741, NULL }, + { "certId", 1073741836, NULL }, + { "certValue", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "certId", 1, NULL }, + { "pkcs-12-CRLBag", 1610612741, NULL }, + { "crlId", 1073741836, NULL }, + { "crlValue", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "crlId", 1, NULL }, + { "pkcs-12-SecretBag", 1610612741, NULL }, + { "secretTypeId", 1073741836, NULL }, + { "secretValue", 541073421, NULL }, + { NULL, 1073743880, "0"}, + { "secretTypeId", 1, NULL }, + { "pkcs-12-PKCS12Attribute", 1073741826, "Attribute"}, + { "pkcs-7-Data", 1073741831, NULL }, + { "pkcs-7-EncryptedData", 1610612741, NULL }, + { "version", 1073741826, "pkcs-7-CMSVersion"}, + { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"}, + { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"}, + { NULL, 4104, "1"}, + { "pkcs-7-EncryptedContentInfo", 1610612741, NULL }, + { "contentType", 1073741826, "pkcs-7-ContentType"}, + { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"}, + { "encryptedContent", 536895490, "pkcs-7-EncryptedContent"}, + { NULL, 4104, "0"}, + { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, + { "pkcs-7-EncryptedContent", 1073741831, NULL }, + { "pkcs-7-UnprotectedAttributes", 1612709903, NULL }, + { "MAX", 1074266122, "1"}, + { NULL, 2, "Attribute"}, + { "ProxyCertInfo", 1610612741, NULL }, + { "pCPathLenConstraint", 1611153411, NULL }, + { "0", 10, "MAX"}, + { "proxyPolicy", 2, "ProxyPolicy"}, + { "ProxyPolicy", 536870917, NULL }, + { "policyLanguage", 1073741836, NULL }, + { "policy", 16391, NULL }, + { NULL, 0, NULL } +}; diff --git a/common/tests/Makefile.am b/common/tests/Makefile.am index e3f2063..be92e8d 100644 --- a/common/tests/Makefile.am +++ b/common/tests/Makefile.am @@ -14,12 +14,10 @@ INCLUDES = \ LDADD = \ $(top_builddir)/common/libp11-library.la \ $(top_builddir)/common/libp11-compat.la \ - $(top_builddir)/common/libp11-data.la \ $(CUTEST_LIBS) \ $(NULL) CHECK_PROGS = \ - test-checksum \ test-dict \ test-array \ test-attrs \ @@ -30,3 +28,21 @@ noinst_PROGRAMS = \ $(CHECK_PROGS) TESTS = $(CHECK_PROGS:=$(EXEEXT)) + +if WITH_ASN1 + +LDADD += \ + $(top_builddir)/common/libp11-data.la \ + $(LIBTASN1_LIBS) + $(NULL) + +CHECK_PROGS += \ + test-checksum + +noinst_PROGRAMS += \ + frob-ku \ + frob-eku \ + frob-cert \ + $(NULL) + +endif # WITH_ASN1 diff --git a/common/tests/frob-cert.c b/common/tests/frob-cert.c new file mode 100644 index 0000000..f8ad392 --- /dev/null +++ b/common/tests/frob-cert.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include <libtasn1.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pkix.asn.h" + +#define err_if_fail(ret, msg) \ + do { if ((ret) != ASN1_SUCCESS) { \ + fprintf (stderr, "%s: %s\n", msg, asn1_strerror (ret)); \ + exit (1); \ + } } while (0) + +static ssize_t +tlv_length (const unsigned char *data, + size_t length) +{ + unsigned char cls; + int counter = 0; + int cb, len; + unsigned long tag; + + if (asn1_get_tag_der (data, length, &cls, &cb, &tag) == ASN1_SUCCESS) { + counter += cb; + len = asn1_get_length_der (data + cb, length - cb, &cb); + counter += cb; + if (len >= 0) { + len += counter; + if (length >= len) + return len; + } + } + + return -1; +} + +int +main (int argc, + char *argv[]) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + node_asn *cert = NULL; + unsigned char *data; + struct stat sb; + int start, end; + ssize_t len; + int ret; + int fd; + + if (argc != 4) { + fprintf (stderr, "usage: frob-cert struct field filename\n"); + return 2; + } + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "definitions: %s\n", message); + return 1; + } + + ret = asn1_create_element (definitions, argv[1], &cert); + err_if_fail (ret, "Certificate"); + + fd = open (argv[3], O_RDONLY); + if (fd == -1) { + fprintf (stderr, "couldn't open file: %s\n", argv[3]); + return 1; + } + + if (fstat (fd, &sb) < 0) { + fprintf (stderr, "couldn't stat file: %s\n", argv[3]); + return 1; + } + + data = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == NULL) { + fprintf (stderr, "couldn't map file: %s\n", argv[3]); + return 1; + } + + ret = asn1_der_decoding (&cert, data, sb.st_size, message); + err_if_fail (ret, message); + + ret = asn1_der_decoding_startEnd (cert, data, sb.st_size, argv[2], &start, &end); + err_if_fail (ret, "asn1_der_decoding_startEnd"); + + len = tlv_length (data + start, sb.st_size - start); + assert (len >= 0); + + fprintf (stderr, "%lu %d %d %ld\n", sb.st_size, start, end, len); + fwrite (data + start, 1, len, stdout); + fflush (stdout); + + munmap (data, sb.st_size); + close (fd); + + asn1_delete_structure (&cert); + asn1_delete_structure (&definitions); + + return 0; +} diff --git a/common/tests/frob-eku.c b/common/tests/frob-eku.c new file mode 100644 index 0000000..42bf50b --- /dev/null +++ b/common/tests/frob-eku.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include <libtasn1.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pkix.asn.h" + +#define err_if_fail(ret, msg) \ + do { if ((ret) != ASN1_SUCCESS) { \ + fprintf (stderr, "%s: %s\n", msg, asn1_strerror (ret)); \ + exit (1); \ + } } while (0) + +int +main (int argc, + char *argv[]) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + node_asn *ekus = NULL; + char *buf; + int len; + int ret; + int i; + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "definitions: %s\n", message); + return 1; + } + + ret = asn1_create_element (definitions, "PKIX1.ExtKeyUsageSyntax", &ekus); + err_if_fail (ret, "ExtKeyUsageSyntax"); + + for (i = 1; i < argc; i++) { + ret = asn1_write_value (ekus, "", "NEW", 1); + err_if_fail (ret, "NEW"); + + ret = asn1_write_value (ekus, "?LAST", argv[i], strlen (argv[i])); + err_if_fail (ret, "asn1_write_value"); + } + + len = 0; + ret = asn1_der_coding (ekus, "", NULL, &len, message); + assert (ret == ASN1_MEM_ERROR); + + buf = malloc (len); + assert (buf != NULL); + ret = asn1_der_coding (ekus, "", buf, &len, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "asn1_der_coding: %s\n", message); + return 1; + } + + fwrite (buf, 1, len, stdout); + fflush (stdout); + + asn1_delete_structure (&ekus); + asn1_delete_structure (&definitions); + + return 0; +} diff --git a/common/tests/frob-ku.c b/common/tests/frob-ku.c new file mode 100644 index 0000000..c0abd88 --- /dev/null +++ b/common/tests/frob-ku.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include <libtasn1.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pkix.asn.h" + +#define err_if_fail(ret, msg) \ + do { if ((ret) != ASN1_SUCCESS) { \ + fprintf (stderr, "%s: %s\n", msg, asn1_strerror (ret)); \ + exit (1); \ + } } while (0) + +enum { + KU_DIGITAL_SIGNATURE = 128, + KU_NON_REPUDIATION = 64, + KU_KEY_ENCIPHERMENT = 32, + KU_DATA_ENCIPHERMENT = 16, + KU_KEY_AGREEMENT = 8, + KU_KEY_CERT_SIGN = 4, + KU_CRL_SIGN = 2, + KU_ENCIPHER_ONLY = 1, + KU_DECIPHER_ONLY = 32768, +}; + +int +main (int argc, + char *argv[]) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + node_asn *ku = NULL; + unsigned int usage = 0; + char bits[2]; + char *buf; + int len; + int ret; + int i; + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "digital-signature") == 0) + usage |= KU_DIGITAL_SIGNATURE; + else if (strcmp (argv[i], "non-repudiation") == 0) + usage |= KU_NON_REPUDIATION; + else if (strcmp (argv[i], "key-encipherment") == 0) + usage |= KU_KEY_ENCIPHERMENT; + else if (strcmp (argv[i], "data-encipherment") == 0) + usage |= KU_DATA_ENCIPHERMENT; + else if (strcmp (argv[i], "key-agreement") == 0) + usage |= KU_KEY_AGREEMENT; + else if (strcmp (argv[i], "key-cert-sign") == 0) + usage |= KU_KEY_CERT_SIGN; + else if (strcmp (argv[i], "crl-sign") == 0) + usage |= KU_CRL_SIGN; + else { + fprintf (stderr, "unsupported or unknown key usage: %s\n", argv[i]); + return 2; + } + } + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "definitions: %s\n", message); + return 1; + } + + ret = asn1_create_element (definitions, "PKIX1.KeyUsage", &ku); + err_if_fail (ret, "KeyUsage"); + + bits[0] = usage & 0xff; + bits[1] = (usage >> 8) & 0xff; + + ret = asn1_write_value (ku, "", bits, 9); + err_if_fail (ret, "asn1_write_value"); + + len = 0; + ret = asn1_der_coding (ku, "", NULL, &len, message); + assert (ret == ASN1_MEM_ERROR); + + buf = malloc (len); + assert (buf != NULL); + ret = asn1_der_coding (ku, "", buf, &len, message); + if (ret != ASN1_SUCCESS) { + fprintf (stderr, "asn1_der_coding: %s\n", message); + return 1; + } + + fwrite (buf, 1, len, stdout); + fflush (stdout); + + asn1_delete_structure (&ku); + asn1_delete_structure (&definitions); + + return 0; +} diff --git a/configure.ac b/configure.ac index 426be4f..63235fd 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,9 @@ esac AC_MSG_RESULT([$os_win32]) AM_CONDITIONAL(OS_WIN32, test "$os_win32" = "yes") +AC_C_BIGENDIAN +AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + # ------------------------------------------------------------------------------ # Checks for libraries and headers @@ -68,8 +71,8 @@ if test "$os_unix" = "yes"; then AC_SEARCH_LIBS([nanosleep], [rt], [], [AC_MSG_ERROR([could not find nanosleep])]) AC_CHECK_MEMBERS([struct dirent.d_type],,,[#include <dirent.h>]) - AC_CHECK_HEADERS([err.h errno.h stdbool.h]) AC_CHECK_FUNCS([getprogname getexecname memdup]) + AC_CHECK_FUNCS([getprogname getexecname strnstr memdup]) # Check if these are declared and/or available to link against AC_CHECK_DECLS([program_invocation_short_name]) @@ -120,6 +123,114 @@ AC_SUBST(p11_user_config_modules) AC_SUBST(p11_module_path) # -------------------------------------------------------------------- +# libtasn1 support + +AC_ARG_WITH([libtasn1], + AS_HELP_STRING([--without-libtasn1], + [Disable dependency on libtasn1]) +) + +if test "$with_libtasn1" != "no"; then + PKG_CHECK_MODULES(LIBTASN1, libtasn1) + AC_SUBST(LIBTASN1_CFLAGS) + AC_SUBST(LIBTASN1_LIBS) + with_libtasn1="yes" +fi + +AM_CONDITIONAL(WITH_ASN1, test "$with_libtasn1" = "yes") + +# -------------------------------------------------------------------- +# Trust Module + +AC_ARG_ENABLE([trust-module], + AS_HELP_STRING([--disable-trust-module], + [Disable building the trust module]) +) + +AC_MSG_CHECKING([if trust module is enabled]) + +if test "$enable_trust_module" != "no"; then + if test "$with_libtasn1" != "yes"; then + AC_MSG_ERROR([need --with-libtasn1 in order to use the trust module.]) + fi + enable_trust_module="yes" +fi + +AC_MSG_RESULT([$enable_trust_module]) +AM_CONDITIONAL(WITH_TRUST_MODULE, test "$enable_trust_module" = "yes") + +AC_ARG_WITH([system-anchors], + AS_HELP_STRING([--with-system-anchors=@<:@path@:>@]: + [files or directories containing system CA anchors]) +) + +AC_MSG_CHECKING([location of system CA anchors]) + +if test "$enable_trust_module" != "yes"; then + if test "$with_system_anchors" != ""; then + AC_MSG_ERROR([need --enable-trust-module in order to use system anchors.]) + fi + with_system_anchors="no" +fi + +# This option was disabled, no anchors +if test "$with_system_anchors" = "no"; then + with_system_anchors="" + AC_MSG_RESULT([disabled]) + +# Option was not set, try to detect +elif test "$with_system_anchors" = ""; then + for f in /etc/pki/tls/certs/ca-bundle.crt \ + /etc/ssl/certs/ca-certificates.crt \ + /etc/ssl/ca-bundle.pem \ + /etc/ssl/ca-bundle.crt; do + if test -f "$f"; then + with_system_anchors="$f" + break + fi + done + + if test "$with_system_anchors" = ""; then + AC_MSG_ERROR([could not find. Use --with-system-anchors=path to set, or --without-system-anchors to disable]) + fi + + AC_MSG_RESULT($with_system_anchors) +else + AC_MSG_RESULT($with_system_anchors) +fi + +AC_DEFINE_UNQUOTED(SYSTEM_ANCHORS, ["$with_system_anchors"], [The system anchor paths]) +AC_SUBST(with_system_anchors) + +AC_ARG_WITH([system-certificates], + AS_HELP_STRING([--with-system-certificates=@<:@path@:>@]: + [files or directories containing additional system certificates]) +) + +AC_MSG_CHECKING([location of additional system certificates]) + +if test "$enable_trust_module" != "yes"; then + if test "$with_system_certificates" != ""; then + AC_MSG_ERROR([need --enable-trust-module in order to use additional system certificates.]) + fi + with_system_certificates="" +fi + +# This option was disabled, no additional certificates +if test "$with_system_certificates" = "no"; then + with_system_certificates="" +fi + +if test "$with_system_certificates" = ""; then + AC_MSG_RESULT([disabled]) +else + AC_MSG_RESULT($with_system_certificates) +fi + +AC_DEFINE_UNQUOTED(SYSTEM_CERTIFICATES, ["$with_system_certificates"], [Additional system certificate paths]) +AC_SUBST(with_system_certificates) + +# -------------------------------------------------------------------- # GTK Doc dnl check for tools @@ -287,12 +398,19 @@ AC_SUBST(GENHTML) P11KIT_LT_RELEASE=$P11KIT_CURRENT:$P11KIT_REVISION:$P11KIT_AGE AC_SUBST(P11KIT_LT_RELEASE) +echo $PACKAGE_VERSION | tr '.' ' ' | while read major minor unused; do + AC_DEFINE_UNQUOTED(PACKAGE_MAJOR, $major, [Major version of package]) + AC_DEFINE_UNQUOTED(PACKAGE_MINOR, $minor, [Minor version of package]) + break +done + eval SHLEXT=$shrext_cmds AC_DEFINE_UNQUOTED(SHLEXT, ["$SHLEXT"], [File extension for shared libraries]) AC_SUBST(SHLEXT) AC_CONFIG_FILES([Makefile build/Makefile + build/certs/Makefile common/Makefile common/tests/Makefile doc/Makefile @@ -303,6 +421,8 @@ AC_CONFIG_FILES([Makefile p11-kit/p11-kit-1.pc p11-kit/pkcs11.conf.example tools/Makefile + trust/Makefile + trust/tests/Makefile ]) AC_OUTPUT @@ -318,4 +438,10 @@ AC_MSG_NOTICE([build options: User global config: $p11_user_config_file User module config directory: $p11_user_config_modules Load relative module paths from: $p11_module_path + + With libtasn1 dependency: $with_libtasn1 + + Build trust module: $enable_trust_module + System certificate anchor paths: $with_system_anchors + Other system certificate paths: $with_system_certificates ]) diff --git a/doc/Makefile.am b/doc/Makefile.am index 1846993..3154215 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -52,6 +52,7 @@ IGNORE_HFILES= \ dict.h \ mock-module.h \ pkcs11.h \ + pkcs11x.h \ private.h \ util.h \ array.h \ @@ -66,6 +67,7 @@ HTML_IMAGES= # e.g. content_files=running.sgml building.sgml changes-2.0.sgml content_files=p11-kit-config.xml p11-kit-sharing.xml \ p11-kit-devel.xml \ + p11-kit-trust.xml \ p11-kit.xml \ $(NULL) diff --git a/doc/p11-kit-config.xml b/doc/p11-kit-config.xml index d35b112..da413e0 100644 --- a/doc/p11-kit-config.xml +++ b/doc/p11-kit-config.xml @@ -167,6 +167,16 @@ critical: yes not present, then any process will load the module.</para> </listitem> </varlistentry> + <varlistentry> + <term>trust-policy</term> + <listitem> + <para>If this setting is present then this module is used to load + trust policy information such as certificate anchors and black lists. + The value should be an integer. Modules with a lower number are loaded + first. Trust policy information in modules loaded later overrides + those loaded first.</para> + </listitem> + </varlistentry> </variablelist> <para>Do not specify both <literal>enable-in</literal> and <literal>disable-in</literal> diff --git a/doc/p11-kit-devel.xml b/doc/p11-kit-devel.xml index f2a1f58..f3acde1 100644 --- a/doc/p11-kit-devel.xml +++ b/doc/p11-kit-devel.xml @@ -131,6 +131,8 @@ $ make install <listitem><para><command>xsltproc</command> is required to build the command manual pages. Use <literal>--enable-doc</literal> to control this dependency.</para></listitem> + <listitem><para><command>libtasn1</command> is required to build the trust + module and code that interacts with certificates.</para></listitem> </itemizedlist> </section> @@ -143,6 +145,10 @@ $ make install <variablelist> <varlistentry> + <term><option>--disable-trust-module</option></term> + <listitem><para>Disables building of the trust policy module.</para></listitem> + </varlistentry> + <varlistentry> <term><option>--disable-debug</option>, <option>--enable-debug</option></term> <listitem><para>By default p11-kit is built with debug symbols assertions and and precondition checks. Enabling the debug option configures even more @@ -164,11 +170,29 @@ $ make install compiler warnings become errors.</para></listitem> </varlistentry> <varlistentry> + <term><option>--with-libtasn1</option>, <option>--without-libtasn1</option></term> + <listitem><para>Build with a dependency on the libtasn1 library. This dependency + allows the trust policy module to be built as well as other code that interacts with + certificates.</para></listitem> + </varlistentry> + <varlistentry> <term><option>--with-module-path</option></term> <listitem><para>Specify the path to look for PKCS#11 modules which were listed in a module config file with a relative path.</para></listitem> </varlistentry> <varlistentry> + <term><option>--with-system-anchors</option></term> + <listitem><para>Specify the files or directories to look for system + certificate anchors. Multiple files and/or directories are specified with + a <literal>:</literal> in between them.</para></listitem> + </varlistentry> + <varlistentry> + <term><option>--with-system-certificates</option></term> + <listitem><para>Specify the files or directories to look for other + non-anchor system certificates. Multiple files and/or directories are + specified with a <literal>:</literal> in between them.</para></listitem> + </varlistentry> + <varlistentry> <term><option>--with-system-config</option></term> <listitem><para>Specify the path to look for p11-kit config files. This usually defaults to something like <literal>/etc/pkcs11</literal></para></listitem> diff --git a/doc/p11-kit-docs.sgml b/doc/p11-kit-docs.sgml index 2d3760a..5627f6f 100644 --- a/doc/p11-kit-docs.sgml +++ b/doc/p11-kit-docs.sgml @@ -13,6 +13,7 @@ <xi:include href="p11-kit-config.xml"/> <xi:include href="p11-kit-sharing.xml"/> + <xi:include href="p11-kit-trust.xml"/> <chapter xml:id="tools"> <title>Command Line Tools</title> diff --git a/doc/p11-kit-trust.xml b/doc/p11-kit-trust.xml new file mode 100644 index 0000000..7496f7b --- /dev/null +++ b/doc/p11-kit-trust.xml @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ +]> +<chapter xml:id="trust"> +<title>Trust Policy Module</title> + + <para>The trust module provides system certificate anchors, blacklists + and other trust policy to crypto libraries applications. This + information is exposed as PKCS#11 objects.</para> + +<section id="trust-files"> + <title>Files loaded by the Module</title> + + <para>The trust module loads certificates and trust policy information + from preconfigured directories and allows them to be looked up via + PKCS#11. The directories can be determined with using the following + commands:</para> + + <itemizedlist> + <listitem> + <para>System Anchors: certificates in these locations + are automatically treated as certificate authority anchors + unless they contain information that prevents that. To check + which locations are being used, run the following command:</para> +<programlisting> +$ pkg-config --variable p11_system_anchors p11-kit-1 +/etc/pki/tls/certs/ca-bundle.trust.crt:/etc/pki/tls/anchors +</programlisting> + </listitem> + <listitem> + <para>System Certificates: certificates in these locations + are not treated as anchors, but simply made available through + the module. To find out which directory is used, run the + following command:</para> +<programlisting> +$ pkg-config --variable p11_system_certificates p11-kit-1 +/etc/pki/tls/other-certs +</programlisting> + </listitem> + </itemizedlist> + + <para>Files in the following formats are supported for loading by the + trust policy module:</para> + + <variablelist> + <varlistentry> + <term>X.509 certificates</term> + <listitem><para>X.509 certificates in raw DER format.</para></listitem> + </varlistentry> + </variablelist> +</section> + +<section id="trust-nss"> + <title>Using the Trust Policy Module with NSS</title> + + <para>The trust policy module is a drop in replacement for the + <literal>libnssckbi.so</literal> module and thus works out of + the box with NSS. The module may be used to replace the + <literal>libnssckbi.so</literal> file via an distribution + specific alternatives mechanism or otherwise.</para> + + <para>Alternatively NSS applications like Firefox or Thunderbird + may be configured to use the trust policy module by adding + the <literal>p11-kit-trust.so</literal> PKCS#11 module via their + GUI or command line configuration.</para> +</section> + +<section id="trust-disable"> + <title>Disabling the Trust Policy Module</title> + + <para>This module is installed and enabled by default. It may + be disabled in the following ways:</para> + + <itemizedlist> + <listitem><para>Use the <option>--disable-trust-module</option> + during the <link linkend="devel-building-configure">p11-kit + build</link>.</para></listitem> + <listitem><para>Disable loading trust policy information + from this module by adding a file to <literal>/etc/pkcs11/modules</literal> + called <literal>p11-kit-trust.module</literal> containing a + <literal>trust-policy:</literal> line.</para></listitem> + <listitem><para>Disable this module completely by + adding a file to <literal>/etc/pkcs11/modules</literal> + called <literal>p11-kit-trust.module</literal> containing a + <literal>enable-in:</literal> line.</para></listitem> + </itemizedlist> + +</section> + +</chapter> diff --git a/doc/style.css b/doc/style.css index e70190a..b4b8d47 100644 --- a/doc/style.css +++ b/doc/style.css @@ -99,10 +99,14 @@ DIV.toc DL { margin-bottom: 0; } -DIV.toc > DL > DT { +DIV.book > DIV.toc > DL > DT { margin-top: 1em; } DIV.toc DT { margin-bottom: 0.3em; } + +TABLE.variablelist SPAN.term { + padding-right: 1em; +} diff --git a/p11-kit/Makefile.am b/p11-kit/Makefile.am index fd0b90a..650fe44 100644 --- a/p11-kit/Makefile.am +++ b/p11-kit/Makefile.am @@ -24,6 +24,7 @@ MODULE_SRCS = \ modules.c \ pkcs11.h \ pin.c \ + pkcs11.h \ proxy.c \ private.h \ messages.c \ diff --git a/p11-kit/conf.c b/p11-kit/conf.c index 68b6343..0f98636 100644 --- a/p11-kit/conf.c +++ b/p11-kit/conf.c @@ -111,43 +111,6 @@ strequal (const char *one, const char *two) return strcmp (one, two) == 0; } -static char * -strconcat (const char *first, - ...) GNUC_NULL_TERMINATED; - -static char * -strconcat (const char *first, - ...) -{ - size_t length = 0; - const char *arg; - char *result, *at; - va_list va; - - va_start (va, first); - - for (arg = first; arg; arg = va_arg (va, const char*)) - length += strlen (arg); - - va_end (va); - - at = result = malloc (length + 1); - return_val_if_fail (result != NULL, NULL); - - va_start (va, first); - - for (arg = first; arg; arg = va_arg (va, const char*)) { - length = strlen (arg); - memcpy (at, arg, length); - at += length; - } - - va_end (va); - - *at = 0; - return result; -} - /* ----------------------------------------------------------------------------- * CONFIG PARSER */ diff --git a/p11-kit/p11-kit-1.pc.in b/p11-kit/p11-kit-1.pc.in index d0d378d..441904d 100644 --- a/p11-kit/p11-kit-1.pc.in +++ b/p11-kit/p11-kit-1.pc.in @@ -10,6 +10,9 @@ p11_module_configs=@p11_package_config_modules@ p11_module_path=@p11_module_path@ proxy_module=@libdir@/p11-kit-proxy.so +p11_system_anchors=@with_system_anchors@ +p11_system_certificates=@with_system_certificates@ + # This is for compatibility. Other packages were using this to determine # the directory they should install their module configs to, so override # this and redirect them to the new location diff --git a/trust/Makefile.am b/trust/Makefile.am new file mode 100644 index 0000000..413bb51 --- /dev/null +++ b/trust/Makefile.am @@ -0,0 +1,52 @@ +NULL = + +SUBDIRS = . tests + +COMMON = $(top_srcdir)/common + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/common \ + $(NULL) + +MODULE_SRCS = \ + parser.c parser.h \ + module.c module.h \ + session.c session.h \ + token.c token.h \ + $(NULL) + +configdir = $(p11_package_config_modules) +config_DATA = p11-kit-trust.module + +moduledir = $(p11_module_path) +module_LTLIBRARIES = \ + p11-kit-trust.la + +p11_kit_trust_la_CFLAGS = \ + $(LIBTASN1_CFLAGS) + +p11_kit_trust_la_LIBADD = \ + $(top_builddir)/common/libp11-data.la \ + $(top_builddir)/common/libp11-library.la \ + $(top_builddir)/common/libp11-compat.la \ + $(LIBTASN1_LIBS) + +p11_kit_trust_la_LDFLAGS = \ + -no-undefined -module -avoid-version \ + -version-info $(P11KIT_LT_RELEASE) \ + -export-symbols-regex 'C_GetFunctionList' \ + $(NULL) + +p11_kit_trust_la_SOURCES = $(MODULE_SRCS) + +noinst_LTLIBRARIES = \ + libtrust-testable.la + +libtrust_testable_la_LDFLAGS = \ + -no-undefined + +libtrust_testable_la_SOURCES = $(MODULE_SRCS) + +EXTRA_DIST = \ + p11-kit-trust.module diff --git a/trust/module.c b/trust/module.c new file mode 100644 index 0000000..ab28095 --- /dev/null +++ b/trust/module.c @@ -0,0 +1,1517 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "config.h" + +#include "attrs.h" +#define P11_DEBUG_FLAG P11_DEBUG_TRUST +#include "debug.h" +#include "dict.h" +#include "library.h" +#include "module.h" +#include "pkcs11.h" +#include "session.h" +#include "token.h" + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#define MANUFACTURER_ID "PKCS#11 Kit " +#define LIBRARY_DESCRIPTION "PKCS#11 Kit Trust Module " +#define SLOT_DESCRIPTION "System Certificates, Trust Anchors, and Black Lists " +#define TOKEN_LABEL "System Trust Anchors and Policy " +#define TOKEN_MODEL "PKCS#11 Kit " +#define TOKEN_SERIAL_NUMBER "1 " + +/* Arbitrary non-zero and non-one choice */ +#define SYSTEM_SLOT_ID 18UL + +static struct _Shared { + p11_dict *sessions; + p11_token *token; + char *anchor_paths; + char *certificate_paths; +} gl = { NULL, NULL }; + +/* Used during FindObjects */ +typedef struct _FindObjects { + CK_ATTRIBUTE *match; + CK_OBJECT_HANDLE *snapshot; + CK_ULONG iterator; +} FindObjects; + +static CK_FUNCTION_LIST sys_function_list; + +static void +find_objects_free (void *data) +{ + FindObjects *find = data; + p11_attrs_free (find->match); + free (find->snapshot); + free (find); +} + +static CK_RV +lookup_session (CK_SESSION_HANDLE handle, + p11_session **session) +{ + p11_session *sess; + + if (!gl.sessions) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + sess = p11_dict_get (gl.sessions, &handle); + if (!sess) + return CKR_SESSION_HANDLE_INVALID; + + if (sess && session) + *session = sess; + return CKR_OK; +} + +static void +parse_argument (char *arg) +{ + char *value; + + value = arg + strcspn (arg, ":="); + if (!*value) + value = NULL; + else + *(value++) = 0; + + if (strcmp (arg, "anchors") == 0) { + free (gl.anchor_paths); + gl.anchor_paths = value ? strdup (value) : NULL; + + } else if (strcmp (arg, "certificates") == 0) { + free (gl.certificate_paths); + gl.certificate_paths = value ? strdup (value) : NULL; + + } else { + p11_message ("unrecognized module argument: %s", arg); + } +} + +static void +parse_arguments (const char *string) +{ + char quote = '\0'; + char *src, *dup, *at, *arg; + + if (!string) + return; + + src = dup = strdup (string); + if (!dup) { + p11_message ("couldn't allocate memory for argument string"); + return; + } + + arg = at = src; + for (src = dup; *src; src++) { + + /* Matching quote */ + if (quote == *src) { + quote = '\0'; + + /* Inside of quotes */ + } else if (quote != '\0') { + if (*src == '\\') { + *at++ = *src++; + if (!*src) { + p11_message ("couldn't parse argument string: %s", string); + goto done; + } + if (*src != quote) + *at++ = '\\'; + } + *at++ = *src; + + /* Space, not inside of quotes */ + } else if (isspace(*src)) { + *at = 0; + parse_argument (arg); + arg = at; + + /* Other character outside of quotes */ + } else { + switch (*src) { + case '\'': + case '"': + quote = *src; + break; + case '\\': + *at++ = *src++; + if (!*src) { + p11_message ("couldn't parse argument string: %s", string); + goto done; + } + /* fall through */ + default: + *at++ = *src; + break; + } + } + } + + + if (at != arg) { + *at = 0; + parse_argument (arg); + } + +done: + free (dup); +} + +static CK_RV +sys_C_Finalize (CK_VOID_PTR reserved) +{ + CK_RV rv = CKR_OK; + + p11_debug ("in"); + + /* WARNING: This function must be reentrant */ + + if (reserved) { + rv = CKR_ARGUMENTS_BAD; + + } else { + p11_lock (); + + if (!gl.sessions) { + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + } else { + free (gl.certificate_paths); + free (gl.anchor_paths); + gl.certificate_paths = gl.anchor_paths = NULL; + + p11_dict_free (gl.sessions); + gl.sessions = NULL; + + p11_token_free (gl.token); + gl.token = NULL; + + rv = CKR_OK; + } + + p11_unlock (); + } + + p11_debug ("out: 0x%lx", rv); + return rv; +} + +static CK_RV +sys_C_Initialize (CK_VOID_PTR init_args) +{ + CK_C_INITIALIZE_ARGS *args = NULL; + int supplied_ok; + CK_RV rv; + + p11_library_init_once (); + + /* WARNING: This function must be reentrant */ + + p11_debug ("in"); + + p11_lock (); + + rv = CKR_OK; + + /* pReserved must be NULL */ + args = init_args; + + /* ALL supplied function pointers need to have the value either NULL or non-NULL. */ + supplied_ok = (args->CreateMutex == NULL && args->DestroyMutex == NULL && + args->LockMutex == NULL && args->UnlockMutex == NULL) || + (args->CreateMutex != NULL && args->DestroyMutex != NULL && + args->LockMutex != NULL && args->UnlockMutex != NULL); + if (!supplied_ok) { + p11_message ("invalid set of mutex calls supplied"); + rv = CKR_ARGUMENTS_BAD; + } + + /* + * When the CKF_OS_LOCKING_OK flag isn't set return an error. + * We must be able to use our pthread functionality. + */ + if (!(args->flags & CKF_OS_LOCKING_OK)) { + p11_message ("can't do without os locking"); + rv = CKR_CANT_LOCK; + } + + /* + * We support setting the socket path and other arguments from from the + * pReserved pointer, similar to how NSS PKCS#11 components are initialized. + */ + if (rv == CKR_OK) { + if (args->pReserved) + parse_arguments ((const char*)args->pReserved); + + gl.sessions = p11_dict_new (p11_dict_ulongptr_hash, + p11_dict_ulongptr_equal, + NULL, p11_session_free); + + gl.token = p11_token_new (gl.anchor_paths ? gl.anchor_paths : SYSTEM_ANCHORS, + gl.certificate_paths ? gl.certificate_paths : SYSTEM_CERTIFICATES); + + if (gl.sessions == NULL || gl.token == NULL) { + warn_if_reached (); + rv = CKR_GENERAL_ERROR; + } + } + + p11_unlock (); + + if (rv != CKR_OK) + sys_C_Finalize (NULL); + + p11_debug ("out: 0x%lx", rv); + return rv; +} + +static CK_RV +sys_C_GetInfo (CK_INFO_PTR info) +{ + CK_RV rv = CKR_OK; + + p11_library_init_once (); + + p11_debug ("in"); + + return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD); + + p11_lock (); + + if (!gl.sessions) + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + p11_unlock (); + + if (rv == CKR_OK) { + memset (info, 0, sizeof (*info)); + info->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; + info->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; + info->libraryVersion.major = PACKAGE_MAJOR; + info->libraryVersion.minor = PACKAGE_MINOR; + info->flags = 0; + strncpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32); + strncpy ((char*)info->libraryDescription, LIBRARY_DESCRIPTION, 32); + } + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list) +{ + /* Can be called before C_Initialize */ + return_val_if_fail (list != NULL, CKR_ARGUMENTS_BAD); + + *list = &sys_function_list; + return CKR_OK; +} + +static CK_RV +sys_C_GetSlotList (CK_BBOOL token_present, + CK_SLOT_ID_PTR slot_list, + CK_ULONG_PTR count) +{ + CK_RV rv = CKR_OK; + + return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + if (!gl.sessions) + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + p11_unlock (); + + if (rv != CKR_OK) { + /* already failed */ + + } else if (!slot_list) { + *count = 1; + rv = CKR_OK; + + } else if (*count < 1) { + *count = 1; + rv = CKR_BUFFER_TOO_SMALL; + + } else { + slot_list[0] = SYSTEM_SLOT_ID; + *count = 1; + rv = CKR_OK; + } + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_GetSlotInfo (CK_SLOT_ID id, + CK_SLOT_INFO_PTR info) +{ + CK_RV rv = CKR_OK; + + return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID); + return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + if (!gl.sessions) + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + p11_unlock (); + + if (rv == CKR_OK) { + memset (info, 0, sizeof (*info)); + info->firmwareVersion.major = 0; + info->firmwareVersion.minor = 0; + info->hardwareVersion.major = 0; + info->hardwareVersion.minor = 0; + info->flags = CKF_TOKEN_PRESENT; + strncpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32); + strncpy ((char*)info->slotDescription, SLOT_DESCRIPTION, 64); + } + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_GetTokenInfo (CK_SLOT_ID id, + CK_TOKEN_INFO_PTR info) +{ + CK_RV rv = CKR_OK; + + return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID); + return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + if (!gl.sessions) + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + p11_unlock (); + + if (rv == CKR_OK) { + memset (info, 0, sizeof (*info)); + info->firmwareVersion.major = 0; + info->firmwareVersion.minor = 0; + info->hardwareVersion.major = 0; + info->hardwareVersion.minor = 0; + info->flags = CKF_TOKEN_INITIALIZED | CKF_WRITE_PROTECTED; + strncpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32); + strncpy ((char*)info->label, TOKEN_LABEL, 32); + strncpy ((char*)info->model, TOKEN_MODEL, 16); + strncpy ((char*)info->serialNumber, TOKEN_SERIAL_NUMBER, 16); + info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE; + info->ulSessionCount = CK_UNAVAILABLE_INFORMATION; + info->ulMaxRwSessionCount = 0; + info->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION; + info->ulMaxPinLen = 0; + info->ulMinPinLen = 0; + info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION; + info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; + info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; + info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; + } + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_GetMechanismList (CK_SLOT_ID id, + CK_MECHANISM_TYPE_PTR mechanism_list, + CK_ULONG_PTR count) +{ + CK_RV rv = CKR_OK; + + return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + *count = 0; + + p11_debug ("out: 0x%lx", rv); + return rv; +} + +static CK_RV +sys_C_GetMechanismInfo (CK_SLOT_ID id, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR info) +{ + return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID); + return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD); + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_InitToken (CK_SLOT_ID id, + CK_UTF8CHAR_PTR pin, + CK_ULONG pin_len, + CK_UTF8CHAR_PTR label) +{ + return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID); + return_val_if_reached (CKR_TOKEN_WRITE_PROTECTED); +} + +static CK_RV +sys_C_WaitForSlotEvent (CK_FLAGS flags, + CK_SLOT_ID_PTR slot, + CK_VOID_PTR reserved) +{ + p11_debug ("not supported"); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +static CK_RV +sys_C_OpenSession (CK_SLOT_ID id, + CK_FLAGS flags, + CK_VOID_PTR user_data, + CK_NOTIFY callback, + CK_SESSION_HANDLE_PTR handle) +{ + p11_session *session; + CK_RV rv = CKR_OK; + + return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID); + return_val_if_fail (handle != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + if (!gl.sessions) { + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + } else if (!(flags & CKF_SERIAL_SESSION)) { + rv = CKR_SESSION_PARALLEL_NOT_SUPPORTED; + + } else if (flags & CKF_RW_SESSION) { + rv = CKR_TOKEN_WRITE_PROTECTED; + + } else { + session = p11_session_new (gl.token); + if (p11_dict_set (gl.sessions, &session->handle, session)) { + rv = CKR_OK; + *handle = session->handle; + p11_debug ("session: %lu", *handle); + } else { + warn_if_reached (); + rv = CKR_GENERAL_ERROR; + } + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_CloseSession (CK_SESSION_HANDLE handle) +{ + CK_RV rv = CKR_OK; + + p11_debug ("in"); + + p11_lock (); + + if (!gl.sessions) { + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + } else if (p11_dict_remove (gl.sessions, &handle)) { + rv = CKR_OK; + + } else { + rv = CKR_SESSION_HANDLE_INVALID; + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_CloseAllSessions (CK_SLOT_ID id) +{ + CK_RV rv = CKR_OK; + + return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID); + + p11_debug ("in"); + + p11_lock (); + + if (!gl.sessions) { + rv = CKR_CRYPTOKI_NOT_INITIALIZED; + + } else { + p11_dict_clear (gl.sessions); + rv = CKR_OK; + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_GetFunctionStatus (CK_SESSION_HANDLE handle) +{ + return CKR_SESSION_PARALLEL_NOT_SUPPORTED; +} + +static CK_RV +sys_C_CancelFunction (CK_SESSION_HANDLE handle) +{ + return CKR_SESSION_PARALLEL_NOT_SUPPORTED; +} + +static CK_RV +sys_C_GetSessionInfo (CK_SESSION_HANDLE handle, + CK_SESSION_INFO_PTR info) +{ + CK_RV rv; + + return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, NULL); + + p11_unlock (); + + if (rv == CKR_OK) { + info->flags = CKF_SERIAL_SESSION; + info->slotID = SYSTEM_SLOT_ID; + info->state = CKS_RO_PUBLIC_SESSION; + info->ulDeviceError = 0; + } + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_InitPIN (CK_SESSION_HANDLE handle, + CK_UTF8CHAR_PTR pin, + CK_ULONG pin_len) +{ + return_val_if_reached (CKR_TOKEN_WRITE_PROTECTED); +} + +static CK_RV +sys_C_SetPIN (CK_SESSION_HANDLE handle, + CK_UTF8CHAR_PTR old_pin, + CK_ULONG old_pin_len, + CK_UTF8CHAR_PTR new_pin, + CK_ULONG new_pin_len) +{ + return_val_if_reached (CKR_TOKEN_WRITE_PROTECTED); +} + +static CK_RV +sys_C_GetOperationState (CK_SESSION_HANDLE handle, + CK_BYTE_PTR operation_state, + CK_ULONG_PTR operation_state_len) +{ + p11_debug ("not supported"); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +static CK_RV +sys_C_SetOperationState (CK_SESSION_HANDLE handle, + CK_BYTE_PTR operation_state, + CK_ULONG operation_state_len, + CK_OBJECT_HANDLE encryption_key, + CK_OBJECT_HANDLE authentication_key) +{ + p11_debug ("not supported"); + return CKR_FUNCTION_NOT_SUPPORTED; +} + +static CK_RV +sys_C_Login (CK_SESSION_HANDLE handle, + CK_USER_TYPE user_type, + CK_UTF8CHAR_PTR pin, + CK_ULONG pin_len) +{ + return_val_if_reached (CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +sys_C_Logout (CK_SESSION_HANDLE handle) +{ + return_val_if_reached (CKR_FUNCTION_NOT_SUPPORTED); +} + +static CK_RV +sys_C_CreateObject (CK_SESSION_HANDLE handle, + CK_ATTRIBUTE_PTR template, + CK_ULONG count, + CK_OBJECT_HANDLE_PTR new_object) +{ + CK_ATTRIBUTE *attrs; + p11_session *session; + CK_BBOOL token; + CK_RV rv; + + return_val_if_fail (new_object != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) { + if (p11_attrs_findn_bool (template, count, CKA_TOKEN, &token) && token) + rv = CKR_TOKEN_WRITE_PROTECTED; + } + + if (rv == CKR_OK) { + attrs = p11_attrs_buildn (NULL, template, count); + rv = p11_session_add_object (session, attrs, new_object); + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_CopyObject (CK_SESSION_HANDLE handle, + CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR template, + CK_ULONG count, + CK_OBJECT_HANDLE_PTR new_object) +{ + CK_BBOOL vfalse = CK_FALSE; + CK_ATTRIBUTE token = { CKA_TOKEN, &vfalse, sizeof (vfalse) }; + p11_session *session; + CK_ATTRIBUTE *original; + CK_ATTRIBUTE *attrs; + CK_BBOOL val; + CK_RV rv; + + return_val_if_fail (new_object != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) { + original = p11_session_get_object (session, object, NULL); + if (original == NULL) + rv = CKR_OBJECT_HANDLE_INVALID; + } + + if (rv == CKR_OK) { + if (p11_attrs_findn_bool (template, count, CKA_TOKEN, &val) && val) + rv = CKR_TOKEN_WRITE_PROTECTED; + } + + if (rv == CKR_OK) { + attrs = p11_attrs_dup (original); + attrs = p11_attrs_buildn (attrs, template, count); + attrs = p11_attrs_build (attrs, &token, NULL); + rv = p11_session_add_object (session, attrs, new_object); + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_DestroyObject (CK_SESSION_HANDLE handle, + CK_OBJECT_HANDLE object) +{ + p11_session *session; + CK_RV rv; + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) + rv = p11_session_del_object (session, object); + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_GetObjectSize (CK_SESSION_HANDLE handle, + CK_OBJECT_HANDLE object, + CK_ULONG_PTR size) +{ + p11_session *session; + CK_RV rv; + + return_val_if_fail (size != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) { + if (p11_session_get_object (session, object, NULL)) { + *size = CK_UNAVAILABLE_INFORMATION; + rv = CKR_OK; + } else { + rv = CKR_OBJECT_HANDLE_INVALID; + } + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_GetAttributeValue (CK_SESSION_HANDLE handle, + CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR template, + CK_ULONG count) +{ + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *result; + CK_ATTRIBUTE *attr; + p11_session *session; + CK_ULONG i; + CK_RV rv; + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) { + attrs = p11_session_get_object (session, object, NULL); + if (attrs == NULL) + rv = CKR_OBJECT_HANDLE_INVALID; + } + + if (rv == CKR_OK) { + for (i = 0; i < count; i++) { + result = template + i; + attr = p11_attrs_find (attrs, result->type); + if (!attr) { + result->ulValueLen = (CK_ULONG)-1; + rv = CKR_ATTRIBUTE_TYPE_INVALID; + continue; + } + + if (!result->pValue) { + result->ulValueLen = attr->ulValueLen; + continue; + } + + if (result->ulValueLen >= attr->ulValueLen) { + memcpy (result->pValue, attr->pValue, attr->ulValueLen); + result->ulValueLen = attr->ulValueLen; + continue; + } + + result->ulValueLen = (CK_ULONG)-1; + rv = CKR_BUFFER_TOO_SMALL; + } + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_SetAttributeValue (CK_SESSION_HANDLE handle, + CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR template, + CK_ULONG count) +{ + p11_session *session; + CK_RV rv; + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) + rv = p11_session_set_object (session, object, template, count); + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_FindObjectsInit (CK_SESSION_HANDLE handle, + CK_ATTRIBUTE_PTR template, + CK_ULONG count) +{ + CK_OBJECT_HANDLE *handle_ptr; + CK_BBOOL want_token_objects; + CK_BBOOL want_session_objects; + CK_BBOOL token; + p11_dict *objects; + FindObjects *find; + p11_session *session; + p11_dictiter iter; + CK_ULONG i; + CK_RV rv; + + p11_debug ("in"); + + p11_lock (); + + /* Are we searching for token objects? */ + if (p11_attrs_findn_bool (template, count, CKA_TOKEN, &token)) { + want_token_objects = token; + want_session_objects = !token; + } else { + want_token_objects = CK_TRUE; + want_session_objects = CK_TRUE; + } + + rv = lookup_session (handle, &session); + + /* Refresh from disk if this session hasn't yet */ + if (rv == CKR_OK && want_token_objects && !session->loaded) { + session->loaded = CK_TRUE; + p11_token_load (gl.token); + } + + if (rv == CKR_OK) { + objects = p11_token_objects (gl.token); + + find = calloc (1, sizeof (FindObjects)); + warn_if_fail (find != NULL); + + /* Make a copy of what we're matching */ + if (find) { + find->match = p11_attrs_buildn (NULL, template, count); + warn_if_fail (find->match != NULL); + + /* Build a session snapshot of all objects */ + find->iterator = 0; + count = p11_dict_size (objects) + p11_dict_size (session->objects) + 1; + find->snapshot = calloc (count, sizeof (CK_OBJECT_HANDLE)); + warn_if_fail (find->snapshot != NULL); + } + + if (find && find->snapshot) { + i = 0; + + if (want_token_objects) { + p11_dict_iterate (objects, &iter); + for ( ; p11_dict_next (&iter, (void *)&handle_ptr, NULL); i++) { + assert (i < count); + find->snapshot[i] = *handle_ptr; + } + } + + if (want_session_objects) { + p11_dict_iterate (session->objects, &iter); + for ( ; p11_dict_next (&iter, (void *)&handle_ptr, NULL); i++) { + assert (i < count); + find->snapshot[i] = *handle_ptr; + } + } + + assert (i < count); + assert (find->snapshot[i] == 0UL); + } + + if (!find || !find->snapshot || !find->match) + rv = CKR_HOST_MEMORY; + else + p11_session_set_operation (session, find_objects_free, find); + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_FindObjects (CK_SESSION_HANDLE handle, + CK_OBJECT_HANDLE_PTR objects, + CK_ULONG max_count, + CK_ULONG_PTR count) +{ + CK_OBJECT_HANDLE object; + CK_ATTRIBUTE *attrs; + FindObjects *find = NULL; + p11_session *session; + CK_ULONG matched; + CK_RV rv; + + return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD); + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) { + if (session->cleanup != find_objects_free) + rv = CKR_OPERATION_NOT_INITIALIZED; + find = session->operation; + } + + if (rv == CKR_OK) { + matched = 0; + while (matched < max_count) { + object = find->snapshot[find->iterator]; + if (!object) + break; + + find->iterator++; + + attrs = p11_session_get_object (session, object, NULL); + if (attrs == NULL) + continue; + + if (p11_attrs_match (attrs, find->match)) { + objects[matched] = object; + matched++; + } + } + + *count = matched; + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_FindObjectsFinal (CK_SESSION_HANDLE handle) +{ + p11_session *session; + CK_RV rv; + + p11_debug ("in"); + + p11_lock (); + + rv = lookup_session (handle, &session); + if (rv == CKR_OK) { + if (session->cleanup != find_objects_free) + rv = CKR_OPERATION_NOT_INITIALIZED; + else + p11_session_set_operation (session, NULL, NULL); + } + + p11_unlock (); + + p11_debug ("out: 0x%lx", rv); + + return rv; +} + +static CK_RV +sys_C_EncryptInit (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_Encrypt (CK_SESSION_HANDLE handle, + CK_BYTE_PTR data, + CK_ULONG data_len, + CK_BYTE_PTR encrypted_data, + CK_ULONG_PTR encrypted_data_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_EncryptUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR part, + CK_ULONG part_len, + CK_BYTE_PTR encrypted_part, + CK_ULONG_PTR encrypted_part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_EncryptFinal (CK_SESSION_HANDLE handle, + CK_BYTE_PTR last_part, + CK_ULONG_PTR last_part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DecryptInit (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_Decrypt (CK_SESSION_HANDLE handle, + CK_BYTE_PTR enc_data, + CK_ULONG enc_data_len, + CK_BYTE_PTR data, + CK_ULONG_PTR data_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DecryptUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR enc_part, + CK_ULONG enc_part_len, + CK_BYTE_PTR part, + CK_ULONG_PTR part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DecryptFinal (CK_SESSION_HANDLE handle, + CK_BYTE_PTR last_part, + CK_ULONG_PTR last_part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DigestInit (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_Digest (CK_SESSION_HANDLE handle, + CK_BYTE_PTR data, + CK_ULONG data_len, + CK_BYTE_PTR digest, + CK_ULONG_PTR digest_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DigestUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR part, + CK_ULONG part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DigestKey (CK_SESSION_HANDLE handle, + CK_OBJECT_HANDLE key) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DigestFinal (CK_SESSION_HANDLE handle, + CK_BYTE_PTR digest, + CK_ULONG_PTR digest_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_SignInit (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_Sign (CK_SESSION_HANDLE handle, + CK_BYTE_PTR data, + CK_ULONG data_len, + CK_BYTE_PTR signature, + CK_ULONG_PTR signature_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_SignUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR part, + CK_ULONG part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_SignFinal (CK_SESSION_HANDLE handle, + CK_BYTE_PTR signature, + CK_ULONG_PTR signature_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_SignRecoverInit (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_SignRecover (CK_SESSION_HANDLE handle, + CK_BYTE_PTR data, + CK_ULONG data_len, + CK_BYTE_PTR signature, + CK_ULONG_PTR signature_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_VerifyInit (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_Verify (CK_SESSION_HANDLE handle, + CK_BYTE_PTR data, + CK_ULONG data_len, + CK_BYTE_PTR signature, + CK_ULONG signature_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_VerifyUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR part, + CK_ULONG part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_VerifyFinal (CK_SESSION_HANDLE handle, + CK_BYTE_PTR signature, + CK_ULONG signature_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_VerifyRecoverInit (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_VerifyRecover (CK_SESSION_HANDLE handle, + CK_BYTE_PTR signature, + CK_ULONG signature_len, + CK_BYTE_PTR data, + CK_ULONG_PTR data_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DigestEncryptUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR part, + CK_ULONG part_len, + CK_BYTE_PTR enc_part, + CK_ULONG_PTR enc_part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DecryptDigestUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR enc_part, + CK_ULONG enc_part_len, + CK_BYTE_PTR part, + CK_ULONG_PTR part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_SignEncryptUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR part, + CK_ULONG part_len, + CK_BYTE_PTR enc_part, + CK_ULONG_PTR enc_part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_DecryptVerifyUpdate (CK_SESSION_HANDLE handle, + CK_BYTE_PTR enc_part, + CK_ULONG enc_part_len, + CK_BYTE_PTR part, + CK_ULONG_PTR part_len) +{ + return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED); +} + +static CK_RV +sys_C_GenerateKey (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_ATTRIBUTE_PTR template, + CK_ULONG count, + CK_OBJECT_HANDLE_PTR key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_GenerateKeyPair (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_ATTRIBUTE_PTR pub_template, + CK_ULONG pub_count, + CK_ATTRIBUTE_PTR priv_template, + CK_ULONG priv_count, + CK_OBJECT_HANDLE_PTR pub_key, + CK_OBJECT_HANDLE_PTR priv_key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_WrapKey (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE wrapping_key, + CK_OBJECT_HANDLE key, + CK_BYTE_PTR wrapped_key, + CK_ULONG_PTR wrapped_key_len) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_UnwrapKey (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE unwrapping_key, + CK_BYTE_PTR wrapped_key, + CK_ULONG wrapped_key_len, + CK_ATTRIBUTE_PTR template, + CK_ULONG count, + CK_OBJECT_HANDLE_PTR key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_DeriveKey (CK_SESSION_HANDLE handle, + CK_MECHANISM_PTR mechanism, + CK_OBJECT_HANDLE base_key, + CK_ATTRIBUTE_PTR template, + CK_ULONG count, + CK_OBJECT_HANDLE_PTR key) +{ + return_val_if_reached (CKR_MECHANISM_INVALID); +} + +static CK_RV +sys_C_SeedRandom (CK_SESSION_HANDLE handle, + CK_BYTE_PTR seed, + CK_ULONG seed_len) +{ + return_val_if_reached (CKR_RANDOM_NO_RNG); +} + +static CK_RV +sys_C_GenerateRandom (CK_SESSION_HANDLE handle, + CK_BYTE_PTR random_data, + CK_ULONG random_len) +{ + return_val_if_reached (CKR_RANDOM_NO_RNG); +} + +/* -------------------------------------------------------------------- + * MODULE ENTRY POINT + */ + +static CK_FUNCTION_LIST sys_function_list = { + { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR }, /* version */ + sys_C_Initialize, + sys_C_Finalize, + sys_C_GetInfo, + sys_C_GetFunctionList, + sys_C_GetSlotList, + sys_C_GetSlotInfo, + sys_C_GetTokenInfo, + sys_C_GetMechanismList, + sys_C_GetMechanismInfo, + sys_C_InitToken, + sys_C_InitPIN, + sys_C_SetPIN, + sys_C_OpenSession, + sys_C_CloseSession, + sys_C_CloseAllSessions, + sys_C_GetSessionInfo, + sys_C_GetOperationState, + sys_C_SetOperationState, + sys_C_Login, + sys_C_Logout, + sys_C_CreateObject, + sys_C_CopyObject, + sys_C_DestroyObject, + sys_C_GetObjectSize, + sys_C_GetAttributeValue, + sys_C_SetAttributeValue, + sys_C_FindObjectsInit, + sys_C_FindObjects, + sys_C_FindObjectsFinal, + sys_C_EncryptInit, + sys_C_Encrypt, + sys_C_EncryptUpdate, + sys_C_EncryptFinal, + sys_C_DecryptInit, + sys_C_Decrypt, + sys_C_DecryptUpdate, + sys_C_DecryptFinal, + sys_C_DigestInit, + sys_C_Digest, + sys_C_DigestUpdate, + sys_C_DigestKey, + sys_C_DigestFinal, + sys_C_SignInit, + sys_C_Sign, + sys_C_SignUpdate, + sys_C_SignFinal, + sys_C_SignRecoverInit, + sys_C_SignRecover, + sys_C_VerifyInit, + sys_C_Verify, + sys_C_VerifyUpdate, + sys_C_VerifyFinal, + sys_C_VerifyRecoverInit, + sys_C_VerifyRecover, + sys_C_DigestEncryptUpdate, + sys_C_DecryptDigestUpdate, + sys_C_SignEncryptUpdate, + sys_C_DecryptVerifyUpdate, + sys_C_GenerateKey, + sys_C_GenerateKeyPair, + sys_C_WrapKey, + sys_C_UnwrapKey, + sys_C_DeriveKey, + sys_C_SeedRandom, + sys_C_GenerateRandom, + sys_C_GetFunctionStatus, + sys_C_CancelFunction, + sys_C_WaitForSlotEvent +}; + +#ifdef OS_WIN32 +__declspec(dllexport) +#endif + +CK_RV +C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list) +{ + return sys_C_GetFunctionList (list); +} + +CK_ULONG +p11_module_next_id (void) +{ + static CK_ULONG unique = 0x10; + return (unique)++; +} diff --git a/trust/module.h b/trust/module.h new file mode 100644 index 0000000..13b928a --- /dev/null +++ b/trust/module.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "pkcs11.h" + +#ifndef P11_MODULE_H_ +#define P11_MODULE_H_ + +CK_ULONG p11_module_next_id (void); + +#endif /* P11_MODULE_H_ */ diff --git a/trust/p11-kit-trust.module b/trust/p11-kit-trust.module new file mode 100644 index 0000000..ad0f254 --- /dev/null +++ b/trust/p11-kit-trust.module @@ -0,0 +1,6 @@ + +# This is a module config for the 'included' p11-kit trust module +module: p11-kit-trust.so + +# The order in which this is loaded in the trust policy +trust-policy: 1 diff --git a/trust/parser.c b/trust/parser.c new file mode 100644 index 0000000..ef72474 --- /dev/null +++ b/trust/parser.c @@ -0,0 +1,1103 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "config.h" + +#include "attrs.h" +#include "checksum.h" +#define P11_DEBUG_FLAG P11_DEBUG_TRUST +#include "debug.h" +#include "dict.h" +#include "library.h" +#include "module.h" +#include "parser.h" +#include "pkcs11x.h" + +#include <libtasn1.h> + +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pkix.asn.h" + +struct _p11_parser { + node_asn *pkix_definitions; + p11_parser_sink sink; + void *sink_data; + const char *probable_label; + int flags; +}; + +typedef int (* parser_func) (p11_parser *parser, + const unsigned char *data, + size_t length); + +static node_asn * +decode_asn1 (p11_parser *parser, + const char *struct_name, + const unsigned char *data, + size_t length, + char *message) +{ + char msg[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + node_asn *definitions; + node_asn *el = NULL; + int ret; + + if (message == NULL) + message = msg; + + if (strncmp (struct_name, "PKIX1.", 6) == 0) { + definitions = parser->pkix_definitions; + + } else { + p11_debug_precond ("unknown prefix for element: %s", struct_name); + return NULL; + } + + ret = asn1_create_element (definitions, struct_name, &el); + if (ret != ASN1_SUCCESS) { + p11_debug_precond ("failed to create element %s at %s: %d", + struct_name, __func__, ret); + return NULL; + } + + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + /* asn1_der_decoding destroys the element if fails */ + ret = asn1_der_decoding (&el, data, length, message); + + if (ret != ASN1_SUCCESS) { + p11_debug ("couldn't parse %s: %s: %s", + struct_name, asn1_strerror (ret), message); + return NULL; + } + + return el; +} + +static void +sink_object (p11_parser *parser, + CK_ATTRIBUTE *attrs) +{ + if (parser->sink) + (parser->sink) (attrs, parser->sink_data); + else + p11_attrs_free (attrs); +} + +#define ID_LENGTH P11_CHECKSUM_SHA1_LENGTH + +static void +id_generate (p11_parser *parser, + CK_BYTE *vid) +{ + CK_ULONG val = p11_module_next_id (); + p11_checksum_sha1 (vid, &val, sizeof (val), NULL); +} + +static CK_ATTRIBUTE * +build_object (p11_parser *parser, + CK_ATTRIBUTE *attrs, + CK_OBJECT_CLASS vclass, + CK_BYTE *vid, + const char *explicit_label) +{ + CK_BBOOL vtrue = CK_TRUE; + CK_BBOOL vfalse = CK_FALSE; + const char *vlabel; + + CK_ATTRIBUTE klass = { CKA_CLASS, &vclass, sizeof (vclass) }; + CK_ATTRIBUTE token = { CKA_TOKEN, &vtrue, sizeof (vtrue) }; + CK_ATTRIBUTE private = { CKA_PRIVATE, &vfalse, sizeof (vfalse) }; + CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &vfalse, sizeof (vfalse) }; + CK_ATTRIBUTE id = { CKA_ID, vid, ID_LENGTH }; + CK_ATTRIBUTE label = { CKA_LABEL, }; + + vlabel = explicit_label ? (char *)explicit_label : parser->probable_label; + if (vlabel) { + label.pValue = (void *)vlabel; + label.ulValueLen = strlen (vlabel); + } else { + label.type = CKA_INVALID; + } + + if (!vid) + id.type = CKA_INVALID; + + return p11_attrs_build (attrs, &klass, &token, &private, &modifiable, + &id, &label, NULL); +} + +static void +calc_check_value (const unsigned char *data, + size_t length, + CK_BYTE *check_value) +{ + unsigned char checksum[P11_CHECKSUM_SHA1_LENGTH]; + p11_checksum_sha1 (checksum, data, length, NULL); + memcpy (check_value, checksum, 3); +} + +static int +atoin (const char *p, + int digits) +{ + int ret = 0, base = 1; + while(--digits >= 0) { + if (p[digits] < '0' || p[digits] > '9') + return -1; + ret += (p[digits] - '0') * base; + base *= 10; + } + return ret; +} + +static int +two_to_four_digit_year (int year) +{ + time_t now; + struct tm tm; + int century, current; + + return_val_if_fail (year >= 0 && year <= 99, -1); + + /* Get the current year */ + now = time (NULL); + return_val_if_fail (now >= 0, -1); + if (!gmtime_r (&now, &tm)) + return_val_if_reached (-1); + + current = (tm.tm_year % 100); + century = (tm.tm_year + 1900) - current; + + /* + * Check if it's within 40 years before the + * current date. + */ + if (current < 40) { + if (year < current) + return century + year; + if (year > 100 - (40 - current)) + return (century - 100) + year; + } else { + if (year < current && year > (current - 40)) + return century + year; + } + + /* + * If it's after then adjust for overflows to + * the next century. + */ + if (year < current) + return century + 100 + year; + else + return century + year; +} + +static bool +parse_utc_time (const char *time, + size_t n_time, + struct tm *when, + int *offset) +{ + const char *p, *e; + int year; + + assert (when != NULL); + assert (time != NULL); + assert (offset != NULL); + + /* YYMMDDhhmmss.ffff Z | +0000 */ + if (n_time < 6 || n_time >= 28) + return false; + + /* Reset everything to default legal values */ + memset (when, 0, sizeof (*when)); + *offset = 0; + when->tm_mday = 1; + + /* Select the digits part of it */ + p = time; + for (e = p; *e >= '0' && *e <= '9'; ++e); + + if (p + 2 <= e) { + year = atoin (p, 2); + p += 2; + + /* + * 40 years in the past is our century. 60 years + * in the future is the next century. + */ + when->tm_year = two_to_four_digit_year (year) - 1900; + } + if (p + 2 <= e) { + when->tm_mon = atoin (p, 2) - 1; + p += 2; + } + if (p + 2 <= e) { + when->tm_mday = atoin (p, 2); + p += 2; + } + if (p + 2 <= e) { + when->tm_hour = atoin (p, 2); + p += 2; + } + if (p + 2 <= e) { + when->tm_min = atoin (p, 2); + p += 2; + } + if (p + 2 <= e) { + when->tm_sec = atoin (p, 2); + p += 2; + } + + if (when->tm_year < 0 || when->tm_year > 9999 || + when->tm_mon < 0 || when->tm_mon > 11 || + when->tm_mday < 1 || when->tm_mday > 31 || + when->tm_hour < 0 || when->tm_hour > 23 || + when->tm_min < 0 || when->tm_min > 59 || + when->tm_sec < 0 || when->tm_sec > 59) + return false; + + /* Make sure all that got parsed */ + if (p != e) + return false; + + /* Now the remaining optional stuff */ + e = time + n_time; + + /* See if there's a fraction, and discard it if so */ + if (p < e && *p == '.' && p + 5 <= e) + p += 5; + + /* See if it's UTC */ + if (p < e && *p == 'Z') { + p += 1; + + /* See if it has a timezone */ + } else if ((*p == '-' || *p == '+') && p + 3 <= e) { + int off, neg; + + neg = *p == '-'; + ++p; + + off = atoin (p, 2) * 3600; + if (off < 0 || off > 86400) + return false; + p += 2; + + if (p + 2 <= e) { + off += atoin (p, 2) * 60; + p += 2; + } + + /* Use TZ offset */ + if (neg) + *offset = 0 - off; + else + *offset = off; + } + + /* Make sure everything got parsed */ + if (p != e) + return false; + + return true; +} + +static bool +parse_general_time (const char *time, + size_t n_time, + struct tm *when, + int *offset) +{ + const char *p, *e; + + assert (time != NULL); + assert (when != NULL); + assert (offset != NULL); + + /* YYYYMMDDhhmmss.ffff Z | +0000 */ + if (n_time < 8 || n_time >= 30) + return false; + + /* Reset everything to default legal values */ + memset (when, 0, sizeof (*when)); + *offset = 0; + when->tm_mday = 1; + + /* Select the digits part of it */ + p = time; + for (e = p; *e >= '0' && *e <= '9'; ++e); + + if (p + 4 <= e) { + when->tm_year = atoin (p, 4) - 1900; + p += 4; + } + if (p + 2 <= e) { + when->tm_mon = atoin (p, 2) - 1; + p += 2; + } + if (p + 2 <= e) { + when->tm_mday = atoin (p, 2); + p += 2; + } + if (p + 2 <= e) { + when->tm_hour = atoin (p, 2); + p += 2; + } + if (p + 2 <= e) { + when->tm_min = atoin (p, 2); + p += 2; + } + if (p + 2 <= e) { + when->tm_sec = atoin (p, 2); + p += 2; + } + + if (when->tm_year < 0 || when->tm_year > 9999 || + when->tm_mon < 0 || when->tm_mon > 11 || + when->tm_mday < 1 || when->tm_mday > 31 || + when->tm_hour < 0 || when->tm_hour > 23 || + when->tm_min < 0 || when->tm_min > 59 || + when->tm_sec < 0 || when->tm_sec > 59) + return false; + + /* Make sure all that got parsed */ + if (p != e) + return false; + + /* Now the remaining optional stuff */ + e = time + n_time; + + /* See if there's a fraction, and discard it if so */ + if (p < e && *p == '.' && p + 5 <= e) + p += 5; + + /* See if it's UTC */ + if (p < e && *p == 'Z') { + p += 1; + + /* See if it has a timezone */ + } else if ((*p == '-' || *p == '+') && p + 3 <= e) { + int off, neg; + + neg = *p == '-'; + ++p; + + off = atoin (p, 2) * 3600; + if (off < 0 || off > 86400) + return false; + p += 2; + + if (p + 2 <= e) { + off += atoin (p, 2) * 60; + p += 2; + } + + /* Use TZ offset */ + if (neg) + *offset = 0 - off; + else + *offset = off; + } + + /* Make sure everything got parsed */ + if (p != e) + return false; + + return true; +} + +static bool +calc_date (node_asn *cert, + const char *field, + CK_DATE *date) +{ + node_asn *choice; + struct tm when; + int tz_offset; + char buf[64]; + time_t timet; + char *sub; + int len; + int ret; + + choice = asn1_find_node (cert, field); + return_val_if_fail (choice != NULL, false); + + len = sizeof (buf) - 1; + ret = asn1_read_value (cert, field, buf, &len); + return_val_if_fail (ret == ASN1_SUCCESS, false); + + sub = strconcat (field, ".", buf, NULL); + + if (strcmp (buf, "generalTime") == 0) { + len = sizeof (buf) - 1; + ret = asn1_read_value (cert, sub, buf, &len); + return_val_if_fail (ret == ASN1_SUCCESS, false); + if (!parse_general_time (buf, len, &when, &tz_offset)) + return_val_if_reached (false); + + } else if (strcmp (buf, "utcTime") == 0) { + len = sizeof (buf) - 1; + ret = asn1_read_value (cert, sub, buf, &len); + return_val_if_fail (ret == ASN1_SUCCESS, false); + if (!parse_utc_time (buf, len - 1, &when, &tz_offset)) + return_val_if_reached (false); + + } else { + return_val_if_reached (false); + } + + free (sub); + + /* In order to work with 32 bit time_t. */ + if (sizeof (time_t) <= 4 && when.tm_year >= 2038) { + timet = (time_t)2145914603; /* 2037-12-31 23:23:23 */ + + /* Convert to seconds since epoch */ + } else { + timet = timegm (&when); + return_val_if_fail (timet >= 0, false); + timet += tz_offset; + } + + if (!gmtime_r (&timet, &when)) + return_val_if_reached (false); + + assert (sizeof (date->year) == 4); + snprintf ((char *)buf, 5, "%04d", 1900 + when.tm_year); + memcpy (date->year, buf, 4); + + assert (sizeof (date->month) == 2); + snprintf ((char *)buf, 3, "%02d", when.tm_mon + 1); + memcpy (date->month, buf, 2); + + assert (sizeof (date->day) == 2); + snprintf ((char *)buf, 3, "%02d", when.tm_mday); + memcpy (date->day, buf, 2); + + return true; +} + +static bool +calc_trusted (p11_parser *parser, + node_asn *cert, + CK_BBOOL *vtrusted) +{ + assert (parser != NULL); + assert (vtrusted != NULL); + + /* + * This calculates CKA_TRUSTED, which is a silly attribute, don't + * read too much into this. The real trust mechinisms are elsewhere. + */ + + *vtrusted = CK_FALSE; + if (parser->flags & P11_PARSE_FLAG_ANCHOR) { + *vtrusted = CK_TRUE; + return true; + } + + /* Don't add this attribute unless anchor */ + return false; +} + +static bool +calc_element (node_asn *el, + const unsigned char *data, + size_t length, + const char *field, + CK_ATTRIBUTE *attr) +{ + int ret; + int start, end; + + ret = asn1_der_decoding_startEnd (el, data, length, field, &start, &end); + return_val_if_fail (ret == ASN1_SUCCESS, false); + return_val_if_fail (end >= start, false); + + attr->pValue = (void *)(data + start); + attr->ulValueLen = (end - start) + 1; + return true; +} + +static CK_ATTRIBUTE * +build_x509_certificate (p11_parser *parser, + CK_ATTRIBUTE *attrs, + node_asn *cert, + const unsigned char *data, + size_t length) +{ + CK_CERTIFICATE_TYPE vx509 = CKC_X_509; + CK_BYTE vchecksum[3]; + + /* TODO: Implement */ + CK_ULONG vcategory = 0; + CK_BBOOL vtrusted = CK_FALSE; + CK_DATE vstart; + CK_DATE vend; + + CK_ATTRIBUTE certificate_type = { CKA_CERTIFICATE_TYPE, &vx509, sizeof (vx509) }; + CK_ATTRIBUTE certificate_category = { CKA_CERTIFICATE_CATEGORY, &vcategory, sizeof (vcategory) }; + CK_ATTRIBUTE value = { CKA_VALUE, (void *)data, length }; + + CK_ATTRIBUTE check_value = { CKA_CHECK_VALUE, &vchecksum, sizeof (vchecksum) }; + CK_ATTRIBUTE trusted = { CKA_TRUSTED, &vtrusted, sizeof (vtrusted) }; + CK_ATTRIBUTE start_date = { CKA_START_DATE, &vstart, sizeof (vstart) }; + CK_ATTRIBUTE end_date = { CKA_END_DATE, &vend, sizeof (vend) }; + CK_ATTRIBUTE subject = { CKA_SUBJECT, }; + CK_ATTRIBUTE issuer = { CKA_ISSUER, }; + CK_ATTRIBUTE serial_number = { CKA_SERIAL_NUMBER, }; + + /* + * The following are not present: + * CKA_URL + * CKA_HASH_OF_SUBJECT_PUBLIC_KEY + * CKA_HASH_OF_ISSUER_PUBLIC_KEY + * CKA_JAVA_MIDP_SECURITY_DOMAIN + */ + + calc_check_value (data, length, vchecksum); + + /* This is a silly trust flag, we set it if the cert is an anchor */ + if (!calc_trusted (parser, cert, &vtrusted)) + trusted.type = CKA_INVALID; + + if (!calc_date (cert, "tbsCertificate.validity.notBefore", &vstart)) + start_date.type = CKA_INVALID; + if (!calc_date (cert, "tbsCertificate.validity.notAfter", &vend)) + end_date.type = CKA_INVALID; + + if (!calc_element (cert, data, length, "tbsCertificate.issuer.rdnSequence", &issuer)) + issuer.type = CKA_INVALID; + if (!calc_element (cert, data, length, "tbsCertificate.subject.rdnSequence", &subject)) + subject.type = CKA_INVALID; + if (!calc_element (cert, data, length, "tbsCertificate.serialNumber", &serial_number)) + serial_number.type = CKA_INVALID; + + return p11_attrs_build (attrs, &certificate_type, &certificate_category, + &check_value, &trusted, &start_date, &end_date, + &subject, &issuer, &serial_number, &value, + NULL); +} + +static unsigned char * +find_extension (node_asn *cert, + const char *extension_oid, + size_t *length) +{ + unsigned char *data = NULL; + char field[128]; + char oid[128]; + int len; + int ret; + int i; + + assert (extension_oid != NULL); + assert (strlen (extension_oid) < sizeof (oid)); + + for (i = 1; ; i++) { + if (snprintf (field, sizeof (field), "tbsCertificate.extensions.?%u.extnID", i) < 0) + return_val_if_reached (NULL); + + len = sizeof (oid) - 1; + ret = asn1_read_value (cert, field, oid, &len); + + /* No more extensions */ + if (ret == ASN1_ELEMENT_NOT_FOUND) + break; + + /* A really, really long extension oid, not looking for it */ + else if (ret == ASN1_MEM_ERROR) + continue; + + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + /* The one we're lookin for? */ + if (strcmp (oid, extension_oid) != 0) + continue; + + if (snprintf (field, sizeof (field), "tbsCertificate.extensions.?%u.extnValue", i) < 0) + return_val_if_reached (NULL); + + len = 0; + ret = asn1_read_value (cert, field, NULL, &len); + return_val_if_fail (ret == ASN1_MEM_ERROR, NULL); + + data = malloc (len); + return_val_if_fail (data != NULL, NULL); + + ret = asn1_read_value (cert, field, data, &len); + return_val_if_fail (ret == ASN1_SUCCESS, NULL); + + *length = len; + break; + } + + return data; +} + +int +p11_parse_key_usage (p11_parser *parser, + const unsigned char *data, + size_t length, + unsigned int *ku) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + unsigned char buf[2]; + node_asn *ext; + int len; + int ret; + + ext = decode_asn1 (parser, "PKIX1.KeyUsage", data, length, message); + if (ext == NULL) + return P11_PARSE_UNRECOGNIZED; + + len = sizeof (buf); + ret = asn1_read_value (ext, "", buf, &len); + return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE); + + /* A bit string, so combine into one set of flags */ + *ku = buf[0] | (buf[1] << 8); + + asn1_delete_structure (&ext); + + return P11_PARSE_SUCCESS; +} + +static unsigned int +decode_ku (p11_parser *parser, + node_asn *cert) +{ + unsigned char *data; + size_t length; + unsigned int ku; + + /* + * If the certificate extension was missing, then *all* key + * usages are to be set. If the extension was invalid, then + * fail safe to none of the key usages. + */ + + data = find_extension (cert, "2.5.29.15", &length); + + if (!data) + return ~0U; + + if (p11_parse_key_usage (parser, data, length, &ku) != P11_PARSE_SUCCESS) { + p11_message ("invalid key usage certificate extension"); + ku = 0U; + } + + free (data); + + return ku; +} + +int +p11_parse_extended_key_usage (p11_parser *parser, + const unsigned char *data, + size_t length, + p11_dict *ekus) +{ + node_asn *ext; + char field[128]; + char *eku; + int len; + int ret; + int i; + + ext = decode_asn1 (parser, "PKIX1.ExtKeyUsageSyntax", data, length, NULL); + if (ext == NULL) + return P11_PARSE_UNRECOGNIZED; + + for (i = 1; ; i++) { + if (snprintf (field, sizeof (field), "?%u", i) < 0) + return_val_if_reached (P11_PARSE_FAILURE); + + len = 0; + ret = asn1_read_value (ext, field, NULL, &len); + if (ret == ASN1_ELEMENT_NOT_FOUND) + break; + + return_val_if_fail (ret == ASN1_MEM_ERROR, P11_PARSE_FAILURE); + + eku = malloc (len + 1); + return_val_if_fail (eku != NULL, P11_PARSE_FAILURE); + + ret = asn1_read_value (ext, field, eku, &len); + return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE); + + if (!p11_dict_set (ekus, eku, eku)) + return_val_if_reached (P11_PARSE_FAILURE); + } + + asn1_delete_structure (&ext); + + return P11_PARSE_SUCCESS; + +} + +static p11_dict * +decode_eku (p11_parser *parser, + node_asn *cert) +{ + unsigned char *data; + p11_dict *ekus; + char *eku; + size_t length; + + ekus = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); + return_val_if_fail (ekus != NULL, NULL); + + /* + * If the certificate extension was missing, then *all* extended key + * usages are to be set. If the extension was invalid, then + * fail safe to none of the extended key usages. + */ + + data = find_extension (cert, "2.5.29.37", &length); + if (data) { + if (p11_parse_extended_key_usage (parser, data, length, ekus) != P11_PARSE_SUCCESS) { + p11_message ("invalid extended key usage certificate extension"); + p11_dict_free (ekus); + ekus = NULL; + } + } else { + /* A star means anything to has_eku() */ + eku = strdup ("*"); + if (!eku || !p11_dict_set (ekus, eku, eku)) + return_val_if_reached (NULL); + } + + free (data); + + return ekus; +} + +static int +has_eku (p11_dict *ekus, + const char *eku) +{ + return ekus != NULL && /* If a "*" present, then any thing allowed */ + (p11_dict_get (ekus, eku) || p11_dict_get (ekus, "*")); +} + +static CK_ATTRIBUTE * +build_nss_trust_object (p11_parser *parser, + CK_ATTRIBUTE *attrs, + node_asn *cert, + const unsigned char *data, + size_t length) +{ + CK_BYTE vsha1_hash[P11_CHECKSUM_SHA1_LENGTH]; + CK_BYTE vmd5_hash[P11_CHECKSUM_MD5_LENGTH]; + CK_BBOOL vfalse = CK_FALSE; + + CK_TRUST vdigital_signature; + CK_TRUST vnon_repudiation; + CK_TRUST vkey_encipherment; + CK_TRUST vdata_encipherment; + CK_TRUST vkey_agreement; + CK_TRUST vkey_cert_sign; + CK_TRUST vcrl_sign; + + CK_TRUST vserver_auth; + CK_TRUST vclient_auth; + CK_TRUST vcode_signing; + CK_TRUST vemail_protection; + CK_TRUST vipsec_end_system; + CK_TRUST vipsec_tunnel; + CK_TRUST vipsec_user; + CK_TRUST vtime_stamping; + + CK_ATTRIBUTE subject = { CKA_SUBJECT, }; + CK_ATTRIBUTE issuer = { CKA_ISSUER, }; + CK_ATTRIBUTE serial_number = { CKA_SERIAL_NUMBER, }; + + CK_ATTRIBUTE md5_hash = { CKA_CERT_MD5_HASH, vmd5_hash, sizeof (vmd5_hash) }; + CK_ATTRIBUTE sha1_hash = { CKA_CERT_SHA1_HASH, vsha1_hash, sizeof (vsha1_hash) }; + + CK_ATTRIBUTE digital_signature = { CKA_TRUST_DIGITAL_SIGNATURE, &vdigital_signature, sizeof (vdigital_signature) }; + CK_ATTRIBUTE non_repudiation = { CKA_TRUST_NON_REPUDIATION, &vnon_repudiation, sizeof (vnon_repudiation) }; + CK_ATTRIBUTE key_encipherment = { CKA_TRUST_KEY_ENCIPHERMENT, &vkey_encipherment, sizeof (vkey_encipherment) }; + CK_ATTRIBUTE data_encipherment = { CKA_TRUST_DATA_ENCIPHERMENT, &vdata_encipherment, sizeof (vdata_encipherment) }; + CK_ATTRIBUTE key_agreement = { CKA_TRUST_KEY_AGREEMENT, &vkey_agreement, sizeof (vkey_agreement) }; + CK_ATTRIBUTE key_cert_sign = { CKA_TRUST_KEY_CERT_SIGN, &vkey_cert_sign, sizeof (vkey_cert_sign) }; + CK_ATTRIBUTE crl_sign = { CKA_TRUST_CRL_SIGN, &vcrl_sign, sizeof (vcrl_sign) }; + + CK_ATTRIBUTE server_auth = { CKA_TRUST_SERVER_AUTH, &vserver_auth, sizeof (vserver_auth) }; + CK_ATTRIBUTE client_auth = { CKA_TRUST_CLIENT_AUTH, &vclient_auth, sizeof (vclient_auth) }; + CK_ATTRIBUTE code_signing = { CKA_TRUST_CODE_SIGNING, &vcode_signing, sizeof (vcode_signing) }; + CK_ATTRIBUTE email_protection = { CKA_TRUST_EMAIL_PROTECTION, &vemail_protection, sizeof (vemail_protection) }; + CK_ATTRIBUTE ipsec_end_system = { CKA_TRUST_IPSEC_END_SYSTEM, &vipsec_end_system, sizeof (vipsec_end_system) }; + CK_ATTRIBUTE ipsec_tunnel = { CKA_TRUST_IPSEC_TUNNEL, &vipsec_tunnel, sizeof (vipsec_tunnel) }; + CK_ATTRIBUTE ipsec_user = { CKA_TRUST_IPSEC_USER, &vipsec_user, sizeof (vipsec_user) }; + CK_ATTRIBUTE time_stamping = { CKA_TRUST_TIME_STAMPING, &vtime_stamping, sizeof (vtime_stamping) }; + + CK_ATTRIBUTE step_up_approved = { CKA_TRUST_STEP_UP_APPROVED, &vfalse, sizeof (vfalse) }; + + p11_dict *ekus; + unsigned int ku; + CK_TRUST value; + CK_TRUST unknown; + + if (!calc_element (cert, data, length, "tbsCertificate.issuer.rdnSequence", &issuer)) + issuer.type = CKA_INVALID; + if (!calc_element (cert, data, length, "tbsCertificate.subject.rdnSequence", &subject)) + subject.type = CKA_INVALID; + if (!calc_element (cert, data, length, "tbsCertificate.serialNumber", &serial_number)) + serial_number.type = CKA_INVALID; + + p11_checksum_md5 (vmd5_hash, data, length, NULL); + p11_checksum_sha1 (vsha1_hash, data, length, NULL); + + unknown = CKT_NETSCAPE_TRUST_UNKNOWN; + if (parser->flags & P11_PARSE_FLAG_ANCHOR) + value = CKT_NETSCAPE_TRUSTED_DELEGATOR; + else + value = CKT_NETSCAPE_TRUSTED; + + ku = decode_ku (parser, cert); + vdigital_signature = (ku & P11_KU_DIGITAL_SIGNATURE) ? value : unknown; + vnon_repudiation = (ku & P11_KU_NON_REPUDIATION) ? value : unknown; + vkey_encipherment = (ku & P11_KU_KEY_ENCIPHERMENT) ? value : unknown; + vkey_agreement = (ku & P11_KU_KEY_AGREEMENT) ? value : unknown; + vkey_cert_sign = (ku & P11_KU_KEY_CERT_SIGN) ? value : unknown; + vcrl_sign = (ku & P11_KU_CRL_SIGN) ? value : unknown; + + ekus = decode_eku (parser, cert); + vserver_auth = has_eku (ekus, P11_EKU_SERVER_AUTH) ? value : unknown; + vclient_auth = has_eku (ekus, P11_EKU_CLIENT_AUTH) ? value : unknown; + vcode_signing = has_eku (ekus, P11_EKU_CODE_SIGNING) ? value : unknown; + vemail_protection = has_eku (ekus, P11_EKU_EMAIL) ? value : unknown; + vipsec_end_system = has_eku (ekus, P11_EKU_IPSEC_END_SYSTEM) ? value : unknown; + vipsec_tunnel = has_eku (ekus, P11_EKU_IPSEC_TUNNEL) ? value : unknown; + vipsec_user = has_eku (ekus, P11_EKU_IPSEC_USER) ? value : unknown; + vtime_stamping = has_eku (ekus, P11_EKU_TIME_STAMPING) ? value : unknown; + p11_dict_free (ekus); + + return p11_attrs_build (attrs, &subject, &issuer, &serial_number, &md5_hash, &sha1_hash, + &digital_signature, &non_repudiation, &key_encipherment, + &data_encipherment, &key_agreement, &key_cert_sign, &crl_sign, + &server_auth, &client_auth, &code_signing, &email_protection, + &ipsec_end_system, &ipsec_tunnel, &ipsec_user, &time_stamping, + &step_up_approved, NULL); + +} + +static int +sink_nss_trust_object (p11_parser *parser, + CK_BYTE *vid, + node_asn *cert, + const unsigned char *data, + size_t length) +{ + CK_ATTRIBUTE *attrs = NULL; + + attrs = build_object (parser, attrs, CKO_NETSCAPE_TRUST, vid, NULL); + return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); + + attrs = build_nss_trust_object (parser, attrs, cert, data, length); + return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); + + sink_object (parser, attrs); + return P11_PARSE_SUCCESS; +} + +static int +sink_x509_certificate (p11_parser *parser, + CK_BYTE *vid, + node_asn *cert, + const unsigned char *data, + size_t length) +{ + CK_ATTRIBUTE *attrs = NULL; + + attrs = build_object (parser, attrs, CKO_CERTIFICATE, vid, NULL); + return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); + + attrs = build_x509_certificate (parser, attrs, cert, data, length); + return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE); + + sink_object (parser, attrs); + return P11_PARSE_SUCCESS; +} + +static int +parse_der_x509_certificate (p11_parser *parser, + const unsigned char *data, + size_t length) +{ + CK_BYTE vid[ID_LENGTH]; + node_asn *cert; + int ret; + + cert = decode_asn1 (parser, "PKIX1.Certificate", data, length, NULL); + if (cert == NULL) + return P11_PARSE_UNRECOGNIZED; + + /* The CKA_ID links related objects */ + id_generate (parser, vid); + + ret = sink_x509_certificate (parser, vid, cert, data, length); + return_val_if_fail (ret == P11_PARSE_SUCCESS, ret); + + ret = sink_nss_trust_object (parser, vid, cert, data, length); + return_val_if_fail (ret == P11_PARSE_SUCCESS, ret); + + asn1_delete_structure (&cert); + return P11_PARSE_SUCCESS; +} + +static parser_func all_parsers[] = { + parse_der_x509_certificate, + NULL, +}; + +p11_parser * +p11_parser_new (void) +{ + char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, }; + node_asn *definitions = NULL; + p11_parser *parser; + int ret; + + ret = asn1_array2tree (pkix_asn1_tab, &definitions, message); + if (ret != ASN1_SUCCESS) { + p11_debug_precond ("failed to load pkix_asn1_tab in %s: %d %s", + __func__, ret, message); + return NULL; + } + + parser = calloc (1, sizeof (p11_parser)); + return_val_if_fail (parser != NULL, NULL); + + parser->pkix_definitions = definitions; + return parser; +} + +void +p11_parser_free (p11_parser *parser) +{ + if (!parser) + return; + + asn1_delete_structure (&parser->pkix_definitions); + free (parser); +} + +int +p11_parse_memory (p11_parser *parser, + const char *filename, + int flags, + const unsigned char *data, + size_t length, + p11_parser_sink sink, + void *sink_data) +{ + int ret = P11_PARSE_UNRECOGNIZED; + char *base; + int i; + + return_val_if_fail (parser != NULL, P11_PARSE_FAILURE); + return_val_if_fail (parser->sink == NULL, P11_PARSE_FAILURE); + + base = basename (filename); + parser->probable_label = base; + parser->sink = sink; + parser->sink_data = sink_data; + parser->flags = flags; + + for (i = 0; all_parsers[i] != NULL; i++) { + ret = (all_parsers[i]) (parser, data, length); + if (ret != P11_PARSE_UNRECOGNIZED) + break; + } + + parser->probable_label = NULL; + parser->sink = NULL; + parser->sink_data = NULL; + parser->flags = 0; + + return ret; +} + +int +p11_parse_file (p11_parser *parser, + const char *filename, + int flags, + p11_parser_sink sink, + void *sink_data) +{ + void *data; + struct stat sb; + int fd; + int ret; + + fd = open (filename, O_RDONLY); + if (fd == -1) { + p11_message ("couldn't open file: %s: %s", filename, strerror (errno)); + return P11_PARSE_FAILURE; + } + + if (fstat (fd, &sb) < 0) { + p11_message ("couldn't stat file: %s: %s", filename, strerror (errno)); + return P11_PARSE_FAILURE; + } + + data = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == NULL) { + p11_message ("couldn't map file: %s: %s", filename, strerror (errno)); + return P11_PARSE_FAILURE; + } + + ret = p11_parse_memory (parser, filename, flags, data, sb.st_size, sink, sink_data); + + munmap (data, sb.st_size); + close (fd); + + return ret; +} diff --git a/trust/parser.h b/trust/parser.h new file mode 100644 index 0000000..44529ba --- /dev/null +++ b/trust/parser.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "dict.h" +#include "pkcs11.h" + +#ifndef P11_PARSER_H_ +#define P11_PARSER_H_ + +enum { + P11_PARSE_FAILURE = -1, + P11_PARSE_UNRECOGNIZED = 0, + P11_PARSE_SUCCESS = 1, +}; + +enum { + P11_PARSE_FLAG_NONE = 0, + P11_PARSE_FLAG_ANCHOR = 1 << 0, +}; + +#define P11_PARSER_FIRST_HANDLE 0xA0000000UL + +#define P11_EKU_SERVER_AUTH "1.3.6.1.5.5.7.3.1" +#define P11_EKU_CLIENT_AUTH "1.3.6.1.5.5.7.3.2" +#define P11_EKU_CODE_SIGNING "1.3.6.1.5.5.7.3.3" +#define P11_EKU_EMAIL "1.3.6.1.5.5.7.3.4" +#define P11_EKU_IPSEC_END_SYSTEM "1.3.6.1.5.5.7.3.5" +#define P11_EKU_IPSEC_TUNNEL "1.3.6.1.5.5.7.3.6" +#define P11_EKU_IPSEC_USER "1.3.6.1.5.5.7.3.7" +#define P11_EKU_TIME_STAMPING "1.3.6.1.5.5.7.3.8" + +enum { + P11_KU_DIGITAL_SIGNATURE = 128, + P11_KU_NON_REPUDIATION = 64, + P11_KU_KEY_ENCIPHERMENT = 32, + P11_KU_DATA_ENCIPHERMENT = 16, + P11_KU_KEY_AGREEMENT = 8, + P11_KU_KEY_CERT_SIGN = 4, + P11_KU_CRL_SIGN = 2, + P11_KU_ENCIPHER_ONLY = 1, + P11_KU_DECIPHER_ONLY = 32768, +}; + +typedef struct _p11_parser p11_parser; + +p11_parser * p11_parser_new (void); + +void p11_parser_free (p11_parser *parser); + +typedef void (* p11_parser_sink) (CK_ATTRIBUTE *attrs, + void *user_data); + +int p11_parse_memory (p11_parser *parser, + const char *filename, + int flags, + const unsigned char *data, + size_t length, + p11_parser_sink sink, + void *sink_data); + +int p11_parse_file (p11_parser *parser, + const char *filename, + int flags, + p11_parser_sink sink, + void *sink_data); + +int p11_parse_key_usage (p11_parser *parser, + const unsigned char *data, + size_t length, + unsigned int *ku); + +int p11_parse_extended_key_usage (p11_parser *parser, + const unsigned char *data, + size_t length, + p11_dict *ekus); + +#endif diff --git a/trust/session.c b/trust/session.c new file mode 100644 index 0000000..070364e --- /dev/null +++ b/trust/session.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "config.h" + +#include "attrs.h" +#define P11_DEBUG_FLAG P11_DEBUG_TRUST +#include "debug.h" +#include "dict.h" +#include "library.h" +#include "pkcs11.h" +#include "module.h" +#include "session.h" + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +typedef struct { + CK_OBJECT_HANDLE handle; + CK_ATTRIBUTE *attrs; +} Object; + +static void +object_free (void *data) +{ + Object *object = data; + p11_attrs_free (object->attrs); + free (object); +} + +p11_session * +p11_session_new (p11_token *token) +{ + p11_session *session; + + session = calloc (1, sizeof (p11_session)); + return_val_if_fail (session != NULL, NULL); + + session->handle = p11_module_next_id (); + + session->objects = p11_dict_new (p11_dict_ulongptr_hash, + p11_dict_ulongptr_equal, + NULL, object_free); + return_val_if_fail (session->objects != NULL, NULL); + + session->token = token; + + return session; +} + +void +p11_session_free (void *data) +{ + p11_session *session = data; + + p11_session_set_operation (session, NULL, NULL); + p11_dict_free (session->objects); + + free (session); +} + +CK_RV +p11_session_add_object (p11_session *session, + CK_ATTRIBUTE *attrs, + CK_OBJECT_HANDLE *handle) +{ + Object *object; + + assert (handle != NULL); + assert (session != NULL); + + return_val_if_fail (attrs != NULL, CKR_GENERAL_ERROR); + + object = malloc (sizeof (Object)); + return_val_if_fail (object != NULL, CKR_HOST_MEMORY); + + object->handle = p11_module_next_id (); + object->attrs = attrs; + + if (!p11_dict_set (session->objects, &object->handle, object)) + return_val_if_reached (CKR_HOST_MEMORY); + + *handle = object->handle; + return CKR_OK; +} + +CK_RV +p11_session_del_object (p11_session *session, + CK_OBJECT_HANDLE handle) +{ + p11_dict *objects; + + assert (session != NULL); + + if (p11_dict_remove (session->objects, &handle)) + return CKR_OK; + + /* Look for in the global objects */ + objects = p11_token_objects (session->token); + if (p11_dict_get (objects, &handle)) + return CKR_TOKEN_WRITE_PROTECTED; + + return CKR_OBJECT_HANDLE_INVALID; +} + +CK_ATTRIBUTE * +p11_session_get_object (p11_session *session, + CK_OBJECT_HANDLE handle, + CK_BBOOL *token) +{ + CK_ATTRIBUTE *attrs; + p11_dict *objects; + Object *object; + + assert (session != NULL); + + object = p11_dict_get (session->objects, &handle); + if (object) { + if (token) + *token = CK_FALSE; + return object->attrs; + } + + objects = p11_token_objects (session->token); + attrs = p11_dict_get (objects, &handle); + if (attrs) { + if (token) + *token = CK_TRUE; + return attrs; + } + + return NULL; +} + +CK_RV +p11_session_set_object (p11_session *session, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *template, + CK_ULONG count) +{ + CK_BBOOL token; + p11_dict *objects; + Object *object; + + assert (session != NULL); + + object = p11_dict_get (session->objects, &handle); + if (object == NULL) { + objects = p11_token_objects (session->token); + if (p11_dict_get (objects, &handle)) + return CKR_TOKEN_WRITE_PROTECTED; + return CKR_OBJECT_HANDLE_INVALID; + } + + if (!p11_attrs_findn_bool (template, count, CKA_TOKEN, &token) && token) + return CKR_TEMPLATE_INCONSISTENT; + + object->attrs = p11_attrs_buildn (object->attrs, template, count); + return CKR_OK; +} + +void +p11_session_set_operation (p11_session *session, + p11_session_cleanup cleanup, + void *operation) +{ + assert (session != NULL); + + if (session->cleanup) + (session->cleanup) (session->operation); + session->cleanup = cleanup; + session->operation = operation; +} diff --git a/trust/session.h b/trust/session.h new file mode 100644 index 0000000..97aedb1 --- /dev/null +++ b/trust/session.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "pkcs11.h" +#include "token.h" + +#ifndef P11_SESSION_H_ +#define P11_SESSION_H_ + +typedef void (* p11_session_cleanup) (void *data); + +typedef struct { + CK_SESSION_HANDLE handle; + p11_dict *objects; + p11_token *token; + CK_BBOOL loaded; + + /* Used by various operations */ + p11_session_cleanup cleanup; + void *operation; +} p11_session; + +p11_session * p11_session_new (p11_token *token); + +void p11_session_free (void *data); + +CK_RV p11_session_add_object (p11_session *session, + CK_ATTRIBUTE *attrs, + CK_OBJECT_HANDLE *handle); + +CK_RV p11_session_del_object (p11_session *session, + CK_OBJECT_HANDLE handle); + +CK_ATTRIBUTE * p11_session_get_object (p11_session *session, + CK_OBJECT_HANDLE handle, + CK_BBOOL *token); + +CK_RV p11_session_set_object (p11_session *session, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *template, + CK_ULONG count); + +void p11_session_set_operation (p11_session *session, + p11_session_cleanup cleanup, + void *operation); + +#endif /* P11_SESSION_H_ */ diff --git a/trust/tests/Makefile.am b/trust/tests/Makefile.am new file mode 100644 index 0000000..2426f8a --- /dev/null +++ b/trust/tests/Makefile.am @@ -0,0 +1,44 @@ + +include $(top_srcdir)/build/Makefile.tests + +NULL = + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(srcdir)/.. \ + -I$(top_srcdir)/common \ + $(CUTEST_CFLAGS) + +noinst_LTLIBRARIES = \ + libtestdata.la + +libtestdata_la_SOURCES = \ + test-data.c test-data.h + +LDADD = \ + $(top_builddir)/trust/libtrust-testable.la \ + $(top_builddir)/common/libp11-data.la \ + $(top_builddir)/common/libp11-library.la \ + $(top_builddir)/common/libp11-compat.la \ + $(builddir)/libtestdata.la \ + $(LIBTASN1_LIBS) \ + $(CUTEST_LIBS) \ + $(NULL) + +CHECK_PROGS = \ + test-parser \ + test-token \ + test-session \ + test-module \ + $(NULL) + +noinst_PROGRAMS = \ + $(CHECK_PROGS) + +TESTS = $(CHECK_PROGS:=$(EXEEXT)) + +EXTRA_DIST = \ + anchors \ + certificates \ + files \ + $(NULL) diff --git a/trust/tests/anchors/cacert3.der b/trust/tests/anchors/cacert3.der Binary files differnew file mode 100644 index 0000000..56f8c88 --- /dev/null +++ b/trust/tests/anchors/cacert3.der diff --git a/trust/tests/anchors/testing-ca.der b/trust/tests/anchors/testing-ca.der Binary files differnew file mode 100644 index 0000000..d3f70ea --- /dev/null +++ b/trust/tests/anchors/testing-ca.der diff --git a/trust/tests/certificates/cacert-ca.der b/trust/tests/certificates/cacert-ca.der Binary files differnew file mode 100644 index 0000000..719b0ff --- /dev/null +++ b/trust/tests/certificates/cacert-ca.der diff --git a/trust/tests/certificates/self-signed-with-eku.der b/trust/tests/certificates/self-signed-with-eku.der Binary files differnew file mode 100644 index 0000000..33e0760 --- /dev/null +++ b/trust/tests/certificates/self-signed-with-eku.der diff --git a/trust/tests/certificates/self-signed-with-ku.der b/trust/tests/certificates/self-signed-with-ku.der Binary files differnew file mode 100644 index 0000000..e6f36e3 --- /dev/null +++ b/trust/tests/certificates/self-signed-with-ku.der diff --git a/trust/tests/files/cacert-ca.der b/trust/tests/files/cacert-ca.der Binary files differnew file mode 100644 index 0000000..719b0ff --- /dev/null +++ b/trust/tests/files/cacert-ca.der diff --git a/trust/tests/files/cacert3.der b/trust/tests/files/cacert3.der Binary files differnew file mode 100644 index 0000000..56f8c88 --- /dev/null +++ b/trust/tests/files/cacert3.der diff --git a/trust/tests/files/self-server.der b/trust/tests/files/self-server.der Binary files differnew file mode 100644 index 0000000..68fe9af --- /dev/null +++ b/trust/tests/files/self-server.der diff --git a/trust/tests/files/testing-server.der b/trust/tests/files/testing-server.der Binary files differnew file mode 100644 index 0000000..cf2de65 --- /dev/null +++ b/trust/tests/files/testing-server.der diff --git a/trust/tests/files/unrecognized-file.txt b/trust/tests/files/unrecognized-file.txt new file mode 100644 index 0000000..4d5bac3 --- /dev/null +++ b/trust/tests/files/unrecognized-file.txt @@ -0,0 +1 @@ +# This file is not recognized by the parser
\ No newline at end of file diff --git a/trust/tests/test-data.c b/trust/tests/test-data.c new file mode 100644 index 0000000..1decf2e --- /dev/null +++ b/trust/tests/test-data.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "CuTest.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "attrs.h" +#include "test-data.h" + +void +test_check_object (CuTest *cu, + CK_ATTRIBUTE *attrs, + CK_OBJECT_CLASS klass, + const char *label) +{ + CK_BBOOL val; + CK_ULONG ulong; + CK_ATTRIBUTE *attr; + + if (!p11_attrs_find_bool (attrs, CKA_TOKEN, &val)) + CuFail (cu, "missing CKA_TOKEN"); + CuAssertIntEquals (cu, CK_TRUE, val); + + if (!p11_attrs_find_bool (attrs, CKA_PRIVATE, &val)) + CuFail (cu, "missing CKA_PRIVATE"); + CuAssertIntEquals (cu, CK_FALSE, val); + + if (!p11_attrs_find_bool (attrs, CKA_MODIFIABLE, &val)) + CuFail (cu, "missing CKA_MODIFIABLE"); + CuAssertIntEquals (cu, CK_FALSE, val); + + if (!p11_attrs_find_ulong (attrs, CKA_CLASS, &ulong)) + CuFail (cu, "missing CKA_CLASS"); + CuAssertIntEquals (cu, klass, ulong); + + if (label) { + attr = p11_attrs_find_valid (attrs, CKA_LABEL); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, label, -1)); + } +} + +void +test_check_cacert3_ca (CuTest *cu, + CK_ATTRIBUTE *attrs, + const char *label) +{ + CK_ATTRIBUTE *attr; + CK_ULONG ulong; + + test_check_object (cu, attrs, CKO_CERTIFICATE, label); + + if (!p11_attrs_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &ulong)) + CuFail (cu, "missing CKA_CERTIFICATE_TYPE"); + CuAssertIntEquals (cu, CKC_X_509, ulong); + + /* TODO: Implement */ + if (!p11_attrs_find_ulong (attrs, CKA_CERTIFICATE_CATEGORY, &ulong)) + CuFail (cu, "missing CKA_CERTIFICATE_CATEGORY"); + CuAssertIntEquals (cu, 0, ulong); + + attr = p11_attrs_find (attrs, CKA_VALUE); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_der, + sizeof (test_cacert3_ca_der))); + + attr = p11_attrs_find_valid (attrs, CKA_CHECK_VALUE); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, "\xad\x7c\x3f", 3)); + + attr = p11_attrs_find (attrs, CKA_START_DATE); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, "20110523", -1)); + + attr = p11_attrs_find_valid (attrs, CKA_END_DATE); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, "20210520", -1)); + + attr = p11_attrs_find (attrs, CKA_SUBJECT); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_subject, + sizeof (test_cacert3_ca_subject))); + + attr = p11_attrs_find (attrs, CKA_ISSUER); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_issuer, + sizeof (test_cacert3_ca_issuer))); + + attr = p11_attrs_find (attrs, CKA_SERIAL_NUMBER); + CuAssertPtrNotNull (cu, attr); + CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_serial, + sizeof (test_cacert3_ca_serial))); +} diff --git a/trust/tests/test-data.h b/trust/tests/test-data.h new file mode 100644 index 0000000..9789493 --- /dev/null +++ b/trust/tests/test-data.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include <sys/types.h> + +#ifndef TEST_DATA_H_ +#define TEST_DATA_H_ + +void test_check_object (CuTest *cu, + CK_ATTRIBUTE *attrs, + CK_OBJECT_CLASS klass, + const char *label); + +void test_check_cacert3_ca (CuTest *cu, + CK_ATTRIBUTE *attrs, + const char *label); + +static const unsigned char test_cacert3_ca_der[] = { + 0x30, 0x82, 0x07, 0x59, 0x30, 0x82, 0x05, 0x41, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x0a, + 0x41, 0x8a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, + 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, + 0x43, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x31, 0x30, 0x35, 0x32, 0x33, 0x31, 0x37, 0x34, 0x38, 0x30, 0x32, 0x5a, 0x17, 0x0d, 0x32, + 0x31, 0x30, 0x35, 0x32, 0x30, 0x31, 0x37, 0x34, 0x38, 0x30, 0x32, 0x5a, 0x30, 0x54, 0x31, 0x14, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x20, + 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x43, + 0x41, 0x63, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f, + 0x6f, 0x74, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, + 0x02, 0x01, 0x00, 0xab, 0x49, 0x35, 0x11, 0x48, 0x7c, 0xd2, 0x26, 0x7e, 0x53, 0x94, 0xcf, 0x43, + 0xa9, 0xdd, 0x28, 0xd7, 0x42, 0x2a, 0x8b, 0xf3, 0x87, 0x78, 0x19, 0x58, 0x7c, 0x0f, 0x9e, 0xda, + 0x89, 0x7d, 0xe1, 0xfb, 0xeb, 0x72, 0x90, 0x0d, 0x74, 0xa1, 0x96, 0x64, 0xab, 0x9f, 0xa0, 0x24, + 0x99, 0x73, 0xda, 0xe2, 0x55, 0x76, 0xc7, 0x17, 0x7b, 0xf5, 0x04, 0xac, 0x46, 0xb8, 0xc3, 0xbe, + 0x7f, 0x64, 0x8d, 0x10, 0x6c, 0x24, 0xf3, 0x61, 0x9c, 0xc0, 0xf2, 0x90, 0xfa, 0x51, 0xe6, 0xf5, + 0x69, 0x01, 0x63, 0xc3, 0x0f, 0x56, 0xe2, 0x4a, 0x42, 0xcf, 0xe2, 0x44, 0x8c, 0x25, 0x28, 0xa8, + 0xc5, 0x79, 0x09, 0x7d, 0x46, 0xb9, 0x8a, 0xf3, 0xe9, 0xf3, 0x34, 0x29, 0x08, 0x45, 0xe4, 0x1c, + 0x9f, 0xcb, 0x94, 0x04, 0x1c, 0x81, 0xa8, 0x14, 0xb3, 0x98, 0x65, 0xc4, 0x43, 0xec, 0x4e, 0x82, + 0x8d, 0x09, 0xd1, 0xbd, 0xaa, 0x5b, 0x8d, 0x92, 0xd0, 0xec, 0xde, 0x90, 0xc5, 0x7f, 0x0a, 0xc2, + 0xe3, 0xeb, 0xe6, 0x31, 0x5a, 0x5e, 0x74, 0x3e, 0x97, 0x33, 0x59, 0xe8, 0xc3, 0x03, 0x3d, 0x60, + 0x33, 0xbf, 0xf7, 0xd1, 0x6f, 0x47, 0xc4, 0xcd, 0xee, 0x62, 0x83, 0x52, 0x6e, 0x2e, 0x08, 0x9a, + 0xa4, 0xd9, 0x15, 0x18, 0x91, 0xa6, 0x85, 0x92, 0x47, 0xb0, 0xae, 0x48, 0xeb, 0x6d, 0xb7, 0x21, + 0xec, 0x85, 0x1a, 0x68, 0x72, 0x35, 0xab, 0xff, 0xf0, 0x10, 0x5d, 0xc0, 0xf4, 0x94, 0xa7, 0x6a, + 0xd5, 0x3b, 0x92, 0x7e, 0x4c, 0x90, 0x05, 0x7e, 0x93, 0xc1, 0x2c, 0x8b, 0xa4, 0x8e, 0x62, 0x74, + 0x15, 0x71, 0x6e, 0x0b, 0x71, 0x03, 0xea, 0xaf, 0x15, 0x38, 0x9a, 0xd4, 0xd2, 0x05, 0x72, 0x6f, + 0x8c, 0xf9, 0x2b, 0xeb, 0x5a, 0x72, 0x25, 0xf9, 0x39, 0x46, 0xe3, 0x72, 0x1b, 0x3e, 0x04, 0xc3, + 0x64, 0x27, 0x22, 0x10, 0x2a, 0x8a, 0x4f, 0x58, 0xa7, 0x03, 0xad, 0xbe, 0xb4, 0x2e, 0x13, 0xed, + 0x5d, 0xaa, 0x48, 0xd7, 0xd5, 0x7d, 0xd4, 0x2a, 0x7b, 0x5c, 0xfa, 0x46, 0x04, 0x50, 0xe4, 0xcc, + 0x0e, 0x42, 0x5b, 0x8c, 0xed, 0xdb, 0xf2, 0xcf, 0xfc, 0x96, 0x93, 0xe0, 0xdb, 0x11, 0x36, 0x54, + 0x62, 0x34, 0x38, 0x8f, 0x0c, 0x60, 0x9b, 0x3b, 0x97, 0x56, 0x38, 0xad, 0xf3, 0xd2, 0x5b, 0x8b, + 0xa0, 0x5b, 0xea, 0x4e, 0x96, 0xb8, 0x7c, 0xd7, 0xd5, 0xa0, 0x86, 0x70, 0x40, 0xd3, 0x91, 0x29, + 0xb7, 0xa2, 0x3c, 0xad, 0xf5, 0x8c, 0xbb, 0xcf, 0x1a, 0x92, 0x8a, 0xe4, 0x34, 0x7b, 0xc0, 0xd8, + 0x6c, 0x5f, 0xe9, 0x0a, 0xc2, 0xc3, 0xa7, 0x20, 0x9a, 0x5a, 0xdf, 0x2c, 0x5d, 0x52, 0x5c, 0xba, + 0x47, 0xd5, 0x9b, 0xef, 0x24, 0x28, 0x70, 0x38, 0x20, 0x2f, 0xd5, 0x7f, 0x29, 0xc0, 0xb2, 0x41, + 0x03, 0x68, 0x92, 0xcc, 0xe0, 0x9c, 0xcc, 0x97, 0x4b, 0x45, 0xef, 0x3a, 0x10, 0x0a, 0xab, 0x70, + 0x3a, 0x98, 0x95, 0x70, 0xad, 0x35, 0xb1, 0xea, 0x85, 0x2b, 0xa4, 0x1c, 0x80, 0x21, 0x31, 0xa9, + 0xae, 0x60, 0x7a, 0x80, 0x26, 0x48, 0x00, 0xb8, 0x01, 0xc0, 0x93, 0x63, 0x55, 0x22, 0x91, 0x3c, + 0x56, 0xe7, 0xaf, 0xdb, 0x3a, 0x25, 0xf3, 0x8f, 0x31, 0x54, 0xea, 0x26, 0x8b, 0x81, 0x59, 0xf9, + 0xa1, 0xd1, 0x53, 0x11, 0xc5, 0x7b, 0x9d, 0x03, 0xf6, 0x74, 0x11, 0xe0, 0x6d, 0xb1, 0x2c, 0x3f, + 0x2c, 0x86, 0x91, 0x99, 0x71, 0x9a, 0xa6, 0x77, 0x8b, 0x34, 0x60, 0xd1, 0x14, 0xb4, 0x2c, 0xac, + 0x9d, 0xaf, 0x8c, 0x10, 0xd3, 0x9f, 0xc4, 0x6a, 0xf8, 0x6f, 0x13, 0xfc, 0x73, 0x59, 0xf7, 0x66, + 0x42, 0x74, 0x1e, 0x8a, 0xe3, 0xf8, 0xdc, 0xd2, 0x6f, 0x98, 0x9c, 0xcb, 0x47, 0x98, 0x95, 0x40, + 0x05, 0xfb, 0xe9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x0d, 0x30, 0x82, 0x02, 0x09, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x75, 0xa8, 0x71, 0x60, 0x4c, + 0x88, 0x13, 0xf0, 0x78, 0xd9, 0x89, 0x77, 0xb5, 0x6d, 0xc5, 0x89, 0xdf, 0xbc, 0xb1, 0x7a, 0x30, + 0x81, 0xa3, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0x9b, 0x30, 0x81, 0x98, 0x80, 0x14, 0x16, + 0xb5, 0x32, 0x1b, 0xd4, 0xc7, 0xf3, 0xe0, 0xe6, 0x8e, 0xf3, 0xbd, 0xd2, 0xb0, 0x3a, 0xee, 0xb2, + 0x39, 0x18, 0xd1, 0xa1, 0x7d, 0xa4, 0x7b, 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, + 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, + 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, + 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, + 0x72, 0x67, 0x82, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x5d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x01, 0x01, 0x04, 0x51, 0x30, 0x4f, 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, + 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x30, 0x28, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x63, + 0x61, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x43, 0x30, 0x41, + 0x30, 0x3f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x90, 0x4a, 0x30, 0x33, 0x30, 0x31, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x68, 0x70, 0x3f, 0x69, 0x64, 0x3d, 0x31, + 0x30, 0x30, 0x34, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, 0x04, 0x27, + 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, + 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x68, + 0x70, 0x3f, 0x69, 0x64, 0x3d, 0x31, 0x30, 0x30, 0x50, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, + 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x43, 0x16, 0x41, 0x54, 0x6f, 0x20, 0x67, 0x65, 0x74, 0x20, 0x79, + 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x46, 0x52, 0x45, 0x45, 0x2c, 0x20, 0x67, 0x6f, + 0x20, 0x74, 0x6f, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, + 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x29, 0x28, 0x85, + 0xae, 0x44, 0xa9, 0xb9, 0xaf, 0xa4, 0x79, 0x13, 0xf0, 0xa8, 0xa3, 0x2b, 0x97, 0x60, 0xf3, 0x5c, + 0xee, 0xe3, 0x2f, 0xc1, 0xf6, 0xe2, 0x66, 0xa0, 0x11, 0xae, 0x36, 0x37, 0x3a, 0x76, 0x15, 0x04, + 0x53, 0xea, 0x42, 0xf5, 0xf9, 0xea, 0xc0, 0x15, 0xd8, 0xa6, 0x82, 0xd9, 0xe4, 0x61, 0xae, 0x72, + 0x0b, 0x29, 0x5c, 0x90, 0x43, 0xe8, 0x41, 0xb2, 0xe1, 0x77, 0xdb, 0x02, 0x13, 0x44, 0x78, 0x47, + 0x55, 0xaf, 0x58, 0xfc, 0xcc, 0x98, 0xf6, 0x45, 0xb9, 0xd1, 0x20, 0xf8, 0xd8, 0x21, 0x07, 0xfe, + 0x6d, 0xaa, 0x73, 0xd4, 0xb3, 0xc6, 0x07, 0xe9, 0x09, 0x85, 0xcc, 0x3b, 0xf2, 0xb6, 0xbe, 0x2c, + 0x1c, 0x25, 0xd5, 0x71, 0x8c, 0x39, 0xb5, 0x2e, 0xea, 0xbe, 0x18, 0x81, 0xba, 0xb0, 0x93, 0xb8, + 0x0f, 0xe3, 0xe6, 0xd7, 0x26, 0x8c, 0x31, 0x5a, 0x72, 0x03, 0x84, 0x52, 0xe6, 0xa6, 0xf5, 0x33, + 0x22, 0x45, 0x0a, 0xc8, 0x0b, 0x0d, 0x8a, 0xb8, 0x36, 0x6f, 0x90, 0x09, 0xa1, 0xab, 0xbd, 0xd7, + 0xd5, 0x4e, 0x2e, 0x71, 0xa2, 0xd4, 0xae, 0xfa, 0xa7, 0x54, 0x2b, 0xeb, 0x35, 0x8d, 0x5a, 0xb7, + 0x54, 0x88, 0x2f, 0xee, 0x74, 0x9f, 0xed, 0x48, 0x16, 0xca, 0x0d, 0x48, 0xd0, 0x94, 0xd3, 0xac, + 0xa4, 0xa2, 0xf6, 0x24, 0xdf, 0x92, 0xe3, 0xbd, 0xeb, 0x43, 0x40, 0x91, 0x6e, 0x1c, 0x18, 0x8e, + 0x56, 0xb4, 0x82, 0x12, 0xf3, 0xa9, 0x93, 0x9f, 0xd4, 0xbc, 0x9c, 0xad, 0x9c, 0x75, 0xee, 0x5a, + 0x97, 0x1b, 0x95, 0xe7, 0x74, 0x2d, 0x1c, 0x0f, 0xb0, 0x2c, 0x97, 0x9f, 0xfb, 0xa9, 0x33, 0x39, + 0x7a, 0xe7, 0x03, 0x3a, 0x92, 0x8e, 0x22, 0xf6, 0x8c, 0x0d, 0xe4, 0xd9, 0x7e, 0x0d, 0x76, 0x18, + 0xf7, 0x01, 0xf9, 0xef, 0x96, 0x96, 0xa2, 0x55, 0x73, 0xc0, 0x3c, 0x71, 0xb4, 0x1d, 0x1a, 0x56, + 0x43, 0xb7, 0xc3, 0x0a, 0x8d, 0x72, 0xfc, 0xe2, 0x10, 0x09, 0x0b, 0x41, 0xce, 0x8c, 0x94, 0xa0, + 0xf9, 0x03, 0xfd, 0x71, 0x73, 0x4b, 0x8a, 0x57, 0x33, 0xe5, 0x8e, 0x74, 0x7e, 0x15, 0x01, 0x00, + 0xe6, 0xcc, 0x4a, 0x1c, 0xe7, 0x7f, 0x95, 0x19, 0x2d, 0xc5, 0xa5, 0x0c, 0x8b, 0xbb, 0xb5, 0xed, + 0x85, 0xb3, 0x5c, 0xd3, 0xdf, 0xb8, 0xb9, 0xf2, 0xca, 0xc7, 0x0d, 0x01, 0x14, 0xac, 0x70, 0x58, + 0xc5, 0x8c, 0x8d, 0x33, 0xd4, 0x9d, 0x66, 0xa3, 0x1a, 0x50, 0x95, 0x23, 0xfc, 0x48, 0xe0, 0x06, + 0x43, 0x12, 0xd9, 0xcd, 0xa7, 0x86, 0x39, 0x2f, 0x36, 0x72, 0xa3, 0x80, 0x10, 0xe4, 0xe1, 0xf3, + 0xd1, 0xcb, 0x5b, 0x1a, 0xc0, 0xe4, 0x80, 0x9a, 0x7c, 0x13, 0x73, 0x06, 0x4f, 0xdb, 0xa3, 0x6b, + 0x24, 0x0a, 0xba, 0xb3, 0x1c, 0xbc, 0x4a, 0x78, 0xbb, 0xe5, 0xe3, 0x75, 0x38, 0xa5, 0x48, 0xa7, + 0xa2, 0x1e, 0xaf, 0x76, 0xd4, 0x5e, 0xf7, 0x38, 0x86, 0x56, 0x5a, 0x89, 0xce, 0xd6, 0xc3, 0xa7, + 0x79, 0xb2, 0x52, 0xa0, 0xc6, 0xf1, 0x85, 0xb4, 0x25, 0x8c, 0xf2, 0x3f, 0x96, 0xb3, 0x10, 0xd9, + 0x8d, 0x6c, 0x57, 0x3b, 0x9f, 0x6f, 0x86, 0x3a, 0x18, 0x82, 0x22, 0x36, 0xc8, 0xb0, 0x91, 0x38, + 0xdb, 0x2a, 0xa1, 0x93, 0xaa, 0x84, 0x3f, 0xf5, 0x27, 0x65, 0xae, 0x73, 0xd5, 0xc8, 0xd5, 0xd3, + 0x77, 0xea, 0x4b, 0x9d, 0xc7, 0x41, 0xbb, 0xc7, 0xc0, 0xe3, 0xa0, 0x3f, 0xe4, 0x7d, 0xa4, 0x8d, + 0x73, 0xe6, 0x12, 0x4b, 0xdf, 0xa1, 0x73, 0x73, 0x73, 0x3a, 0x80, 0xe8, 0xd5, 0xcb, 0x8e, 0x2f, + 0xcb, 0xea, 0x13, 0xa7, 0xd6, 0x41, 0x8b, 0xac, 0xfa, 0x3c, 0x89, 0xd7, 0x24, 0xf5, 0x4e, 0xb4, + 0xe0, 0x61, 0x92, 0xb7, 0xf3, 0x37, 0x98, 0xc4, 0xbe, 0x96, 0xa3, 0xb7, 0x8a, +}; + +static const char test_cacert3_ca_subject[] = { + 0x30, 0x54, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x43, 0x41, 0x63, + 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x15, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, + 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x13, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, + 0x33, 0x20, 0x52, 0x6f, 0x6f, 0x74, +}; + +static const char test_cacert3_ca_issuer[] = { + 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, + 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, + 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, +}; + +static const char test_cacert3_ca_serial[] = { + 0x02, 0x03, 0x0a, 0x41, 0x8a, +}; + +static const char test_ku_ds_and_np[] = { + 0x03, 0x03, 0x07, 0xc0, 0x00, +}; + +static const char test_ku_none[] = { + 0x03, 0x03, 0x07, 0x00, 0x00, +}; + +static const char test_ku_cert_crl_sign[] = { + 0x03, 0x03, 0x07, 0x06, 0x00, +}; + +static const char test_eku_server_and_client[] = { + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, +}; + +static const char test_eku_none[] = { + 0x30, 0x00, +}; + +static const char test_eku_client_email_and_timestamp[] = { + 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x08, +}; + +#endif /* TEST_DATA_H_ */ diff --git a/trust/tests/test-module.c b/trust/tests/test-module.c new file mode 100644 index 0000000..8bd8e10 --- /dev/null +++ b/trust/tests/test-module.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "CuTest.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "attrs.h" +#include "checksum.h" +#include "debug.h" +#include "library.h" +#include "pkcs11x.h" +#include "test-data.h" +#include "token.h" + +struct { + CK_FUNCTION_LIST *module; + CK_SLOT_ID slot; + CK_SESSION_HANDLE session; +} test; + +static void +setup (CuTest *cu) +{ + CK_C_INITIALIZE_ARGS args; + const char *anchors; + const char *certs; + char *arguments; + CK_ULONG count; + CK_RV rv; + + memset (&test, 0, sizeof (test)); + + /* This is the entry point of the trust module, linked to this test */ + rv = C_GetFunctionList (&test.module); + CuAssertTrue (cu, rv == CKR_OK); + + memset (&args, 0, sizeof (args)); + anchors = SRCDIR "/anchors:" SRCDIR "/files/cacert-ca.der"; + certs = SRCDIR "/certificates"; + if (asprintf (&arguments, "anchors='%s' certificates='%s'", anchors, certs) < 0) + CuAssertTrue (cu, false && "not reached"); + args.pReserved = arguments; + args.flags = CKF_OS_LOCKING_OK; + + rv = test.module->C_Initialize (&args); + CuAssertTrue (cu, rv == CKR_OK); + + free (arguments); + + count = 1; + rv = test.module->C_GetSlotList (CK_TRUE, &test.slot, &count); + CuAssertTrue (cu, rv == CKR_OK); + CuAssertTrue (cu, count == 1); + + rv = test.module->C_OpenSession (test.slot, CKF_SERIAL_SESSION, NULL, NULL, &test.session); + CuAssertTrue (cu, rv == CKR_OK); +} + +static void +teardown (CuTest *cu) +{ + CK_RV rv; + + rv = test.module->C_CloseSession (test.session); + CuAssertTrue (cu, rv == CKR_OK); + + rv = test.module->C_Finalize (NULL); + CuAssertTrue (cu, rv == CKR_OK); + + memset (&test, 0, sizeof (test)); +} + +static CK_ULONG +find_objects (CuTest *cu, + CK_ATTRIBUTE *match, + CK_OBJECT_HANDLE *objects, + CK_ULONG num_objects) +{ + CK_RV rv; + CK_ULONG count; + + count = p11_attrs_count (match); + + rv = test.module->C_FindObjectsInit (test.session, match, count); + CuAssertTrue (cu, rv == CKR_OK); + rv = test.module->C_FindObjects (test.session, objects, num_objects, &num_objects); + CuAssertTrue (cu, rv == CKR_OK); + rv = test.module->C_FindObjectsFinal (test.session); + CuAssertTrue (cu, rv == CKR_OK); + + return num_objects; +} + +static void +check_trust_object_equiv (CuTest *cu, + CK_OBJECT_HANDLE trust, + CK_ATTRIBUTE *cert) +{ + unsigned char subject[1024]; + unsigned char issuer[1024]; + unsigned char serial[128]; + CK_BBOOL modifiable; + CK_BBOOL private; + CK_BBOOL token; + CK_RV rv; + + /* The following attributes should be equivalent to the certificate */ + CK_ATTRIBUTE equiv[] = { + { CKA_TOKEN, &token, sizeof (token) }, + { CKA_PRIVATE, &private, sizeof (private) }, + { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) }, + { CKA_ISSUER, issuer, sizeof (issuer) }, + { CKA_SUBJECT, subject, sizeof (subject) }, + { CKA_SERIAL_NUMBER, serial, sizeof (serial) }, + { CKA_INVALID, }, + }; + + rv = test.module->C_GetAttributeValue (test.session, trust, equiv, 6); + CuAssertTrue (cu, rv == CKR_OK); + + CuAssertTrue (cu, p11_attrs_match (cert, equiv)); +} + +static void +check_trust_object_hashes (CuTest *cu, + CK_OBJECT_HANDLE trust, + CK_ATTRIBUTE *cert) +{ + unsigned char sha1[P11_CHECKSUM_SHA1_LENGTH]; + unsigned char md5[P11_CHECKSUM_MD5_LENGTH]; + unsigned char check[128]; + CK_ATTRIBUTE *value; + CK_RV rv; + + CK_ATTRIBUTE hashes[] = { + { CKA_CERT_SHA1_HASH, sha1, sizeof (sha1) }, + { CKA_CERT_MD5_HASH, md5, sizeof (md5) }, + { CKA_INVALID, }, + }; + + rv = test.module->C_GetAttributeValue (test.session, trust, hashes, 2); + CuAssertTrue (cu, rv == CKR_OK); + + value = p11_attrs_find (cert, CKA_VALUE); + CuAssertPtrNotNull (cu, value); + + p11_checksum_md5 (check, value->pValue, value->ulValueLen, NULL); + CuAssertTrue (cu, memcmp (md5, check, sizeof (md5)) == 0); + + p11_checksum_sha1 (check, value->pValue, value->ulValueLen, NULL); + CuAssertTrue (cu, memcmp (sha1, check, sizeof (sha1)) == 0); +} + +static void +check_has_trust_object (CuTest *cu, + CK_ATTRIBUTE *cert) +{ + CK_OBJECT_CLASS trust_object = CKO_NETSCAPE_TRUST; + CK_ATTRIBUTE klass = { CKA_CLASS, &trust_object, sizeof (trust_object) }; + CK_OBJECT_HANDLE objects[2]; + CK_ATTRIBUTE *match; + CK_ATTRIBUTE *attr; + CK_ULONG count; + + attr = p11_attrs_find (cert, CKA_ID); + CuAssertPtrNotNull (cu, attr); + + match = p11_attrs_build (NULL, &klass, attr, NULL); + count = find_objects (cu, match, objects, 2); + CuAssertIntEquals (cu, 1, count); + + check_trust_object_equiv (cu, objects[0], cert); + check_trust_object_hashes (cu, objects[0], cert); +} + +static void +check_certificate (CuTest *cu, + CK_OBJECT_HANDLE handle) +{ + unsigned char label[4096]= { 0, }; + CK_OBJECT_CLASS klass; + unsigned char value[4096]; + unsigned char subject[1024]; + unsigned char issuer[1024]; + unsigned char serial[128]; + unsigned char id[128]; + CK_CERTIFICATE_TYPE type; + CK_BBOOL val; + CK_BYTE check[3]; + CK_DATE start; + CK_DATE end; + CK_ULONG category; + CK_BBOOL modifiable; + CK_BBOOL private; + CK_BBOOL token; + CK_RV rv; + + CK_ATTRIBUTE attrs[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_TOKEN, &token, sizeof (token) }, + { CKA_PRIVATE, &private, sizeof (private) }, + { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) }, + { CKA_VALUE, value, sizeof (value) }, + { CKA_ISSUER, issuer, sizeof (issuer) }, + { CKA_SUBJECT, subject, sizeof (subject) }, + { CKA_CERTIFICATE_TYPE, &type, sizeof (type) }, + { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) }, + { CKA_START_DATE, &start, sizeof (start) }, + { CKA_END_DATE, &end, sizeof (end) }, + { CKA_SERIAL_NUMBER, serial, sizeof (serial) }, + { CKA_CHECK_VALUE, check, sizeof (check) }, + { CKA_ID, id, sizeof (id) }, + { CKA_LABEL, label, sizeof (label) }, + { CKA_INVALID, }, + }; + + /* Note that we don't pass the CKA_INVALID attribute in */ + rv = test.module->C_GetAttributeValue (test.session, handle, attrs, 15); + CuAssertTrue (cu, rv == CKR_OK); + + /* If this is the cacert3 certificate, check its values */ + if (memcmp (value, test_cacert3_ca_der, sizeof (test_cacert3_ca_der)) == 0) { + CK_BBOOL trusted; + + CK_ATTRIBUTE anchor[] = { + { CKA_TRUSTED, &trusted, sizeof (trusted) }, + { CKA_INVALID, }, + }; + + test_check_cacert3_ca (cu, attrs, NULL); + + /* Get anchor specific attributes */ + rv = test.module->C_GetAttributeValue (test.session, handle, anchor, 1); + CuAssertTrue (cu, rv == CKR_OK); + + /* It lives in the trusted directory */ + if (!p11_attrs_find_bool (anchor, CKA_TRUSTED, &val)) + CuFail (cu, "missing CKA_TRUSTED"); + CuAssertIntEquals (cu, CK_TRUE, val); + + /* Other certificates, we can't check the values */ + } else { + test_check_object (cu, attrs, CKO_CERTIFICATE, NULL); + } + + check_has_trust_object (cu, attrs); +} + +static void +test_find_certificates (CuTest *cu) +{ + CK_OBJECT_CLASS klass = CKO_CERTIFICATE; + + CK_ATTRIBUTE match[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_INVALID, } + }; + + CK_OBJECT_HANDLE objects[16]; + CK_ULONG count; + CK_ULONG i; + + setup (cu); + + count = find_objects (cu, match, objects, 16); + CuAssertIntEquals (cu, 6, count); + + for (i = 0; i < count; i++) + check_certificate (cu, objects[i]); + + teardown (cu); +} + +int +main (void) +{ + CuString *output = CuStringNew (); + CuSuite* suite = CuSuiteNew (); + int ret; + + setenv ("P11_KIT_STRICT", "1", 1); + p11_debug_init (); + /* p11_message_quiet (); */ + + SUITE_ADD_TEST (suite, test_find_certificates); + + CuSuiteRun (suite); + CuSuiteSummary (suite, output); + CuSuiteDetails (suite, output); + printf ("%s\n", output->buffer); + ret = suite->failCount; + CuSuiteDelete (suite); + CuStringDelete (output); + + return ret; +} diff --git a/trust/tests/test-parser.c b/trust/tests/test-parser.c new file mode 100644 index 0000000..c224669 --- /dev/null +++ b/trust/tests/test-parser.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "CuTest.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "array.h" +#include "attrs.h" +#include "debug.h" +#include "library.h" +#include "parser.h" +#include "test-data.h" + +struct { + p11_parser *parser; + p11_array *objects; +} test; + +static void +setup (CuTest *cu) +{ + test.parser = p11_parser_new (); + CuAssertPtrNotNull (cu, test.parser); + + test.objects = p11_array_new (p11_attrs_free); + CuAssertPtrNotNull (cu, test.objects); +} + +static void +teardown (CuTest *cu) +{ + p11_parser_free (test.parser); + p11_array_free (test.objects); + memset (&test, 0, sizeof (test)); +} + +static void +on_parse_object (CK_ATTRIBUTE *attrs, + void *data) +{ + CuTest *cu = data; + + CuAssertPtrNotNull (cu, attrs); + CuAssertTrue (cu, p11_attrs_count (attrs) > 0); + + p11_array_push (test.objects, attrs); +} + +static void +test_parse_der_certificate (CuTest *cu) +{ + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *attr; + int ret; + + setup (cu); + + ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", + 0, on_parse_object, cu); + CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); + + /* Should have gotten certificate and a trust object */ + CuAssertIntEquals (cu, 2, test.objects->num); + + attrs = test.objects->elem[0]; + test_check_cacert3_ca (cu, attrs, NULL); + + attr = p11_attrs_find (attrs, CKA_TRUSTED); + CuAssertPtrEquals (cu, NULL, attr); + + teardown (cu); +} + +static void +test_parse_anchor (CuTest *cu) +{ + CK_ATTRIBUTE *attrs; + CK_BBOOL val; + int ret; + + setup (cu); + + ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", + P11_PARSE_FLAG_ANCHOR, on_parse_object, cu); + CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); + + /* Should have gotten a certificate and a trust object */ + CuAssertIntEquals (cu, 2, test.objects->num); + + attrs = test.objects->elem[0]; + test_check_cacert3_ca (cu, attrs, NULL); + + if (!p11_attrs_find_bool (attrs, CKA_TRUSTED, &val)) + CuFail (cu, "missing CKA_TRUSTED"); + CuAssertIntEquals (cu, CK_TRUE, val); + + teardown (cu); +} + +/* TODO: A certificate that uses generalTime needs testing */ + +static void +test_parse_no_sink (CuTest *cu) +{ + int ret; + + setup (cu); + + ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", + 0, NULL, NULL); + CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); + + teardown (cu); +} + +static void +test_parse_invalid_file (CuTest *cu) +{ + int ret; + + setup (cu); + + ret = p11_parse_file (test.parser, "/nonexistant", 0, on_parse_object, cu); + CuAssertIntEquals (cu, P11_PARSE_FAILURE, ret); + + teardown (cu); +} + +static void +test_parse_unrecognized (CuTest *cu) +{ + int ret; + + setup (cu); + + ret = p11_parse_file (test.parser, SRCDIR "/files/unrecognized-file.txt", + 0, on_parse_object, cu); + CuAssertIntEquals (cu, P11_PARSE_UNRECOGNIZED, ret); + + teardown (cu); +} + +struct { + const char *eku; + size_t length; + const char *expected[16]; +} extended_key_usage_fixtures[] = { + { test_eku_server_and_client, sizeof (test_eku_server_and_client), + { P11_EKU_CLIENT_AUTH, P11_EKU_SERVER_AUTH, NULL }, }, + { test_eku_none, sizeof (test_eku_none), + { NULL, }, }, + { test_eku_client_email_and_timestamp, sizeof (test_eku_client_email_and_timestamp), + { P11_EKU_CLIENT_AUTH, P11_EKU_EMAIL, P11_EKU_TIME_STAMPING }, }, + { NULL }, +}; + +static void +test_parse_extended_key_usage (CuTest *cu) +{ + p11_dict *ekus; + int i, j; + int ret; + + setup (cu); + + for (i = 0; extended_key_usage_fixtures[i].eku != NULL; i++) { + ekus = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); + + ret = p11_parse_extended_key_usage (test.parser, + (const unsigned char *)extended_key_usage_fixtures[i].eku, + extended_key_usage_fixtures[i].length, ekus); + CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); + + for (j = 0; extended_key_usage_fixtures[i].expected[j] != NULL; j++) + CuAssertTrue (cu, p11_dict_get (ekus, extended_key_usage_fixtures[i].expected[j]) != NULL); + CuAssertIntEquals (cu, j, p11_dict_size (ekus)); + + p11_dict_free (ekus); + } + + teardown (cu); +} + +static void +test_bad_extended_key_usage (CuTest *cu) +{ + p11_dict *ekus; + int ret; + + setup (cu); + + ekus = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL); + + ret = p11_parse_extended_key_usage (test.parser, (const unsigned char *)"blah", 4, ekus); + CuAssertIntEquals (cu, P11_PARSE_UNRECOGNIZED, ret); + + p11_dict_free (ekus); + + teardown (cu); +} + +struct { + const char *ku; + size_t length; + unsigned int expected; +} key_usage_fixtures[] = { + { test_ku_ds_and_np, sizeof (test_ku_ds_and_np), P11_KU_DIGITAL_SIGNATURE | P11_KU_NON_REPUDIATION }, + { test_ku_none, sizeof (test_ku_none), 0 }, + { test_ku_cert_crl_sign, sizeof (test_ku_cert_crl_sign), P11_KU_KEY_CERT_SIGN | P11_KU_CRL_SIGN }, + { NULL }, +}; + +static void +test_parse_key_usage (CuTest *cu) +{ + unsigned int ku; + int i; + int ret; + + setup (cu); + + for (i = 0; key_usage_fixtures[i].ku != NULL; i++) { + ku = 0; + + ret = p11_parse_key_usage (test.parser, + (const unsigned char *)key_usage_fixtures[i].ku, + key_usage_fixtures[i].length, &ku); + CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); + + CuAssertIntEquals (cu, key_usage_fixtures[i].expected, ku); + } + + teardown (cu); +} + +static void +test_bad_key_usage (CuTest *cu) +{ + unsigned int ku; + int ret; + + setup (cu); + + ret = p11_parse_key_usage (test.parser, (const unsigned char *)"blah", 4, &ku); + CuAssertIntEquals (cu, P11_PARSE_UNRECOGNIZED, ret); + + teardown (cu); +} + +int +main (void) +{ + CuString *output = CuStringNew (); + CuSuite* suite = CuSuiteNew (); + int ret; + + setenv ("P11_KIT_STRICT", "1", 1); + p11_debug_init (); + p11_message_quiet (); + + SUITE_ADD_TEST (suite, test_parse_der_certificate); + SUITE_ADD_TEST (suite, test_parse_anchor); + SUITE_ADD_TEST (suite, test_parse_no_sink); + SUITE_ADD_TEST (suite, test_parse_invalid_file); + SUITE_ADD_TEST (suite, test_parse_unrecognized); + SUITE_ADD_TEST (suite, test_bad_extended_key_usage); + SUITE_ADD_TEST (suite, test_parse_extended_key_usage); + SUITE_ADD_TEST (suite, test_bad_key_usage); + SUITE_ADD_TEST (suite, test_parse_key_usage); + + CuSuiteRun (suite); + CuSuiteSummary (suite, output); + CuSuiteDetails (suite, output); + printf ("%s\n", output->buffer); + ret = suite->failCount; + CuSuiteDelete (suite); + CuStringDelete (output); + + return ret; +} diff --git a/trust/tests/test-session.c b/trust/tests/test-session.c new file mode 100644 index 0000000..48c9146 --- /dev/null +++ b/trust/tests/test-session.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "CuTest.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "attrs.h" +#include "debug.h" +#include "library.h" +#include "session.h" +#include "token.h" + +struct { + p11_token *token; + p11_session *session; +} test; + +static void +setup (CuTest *cu) +{ + test.token = p11_token_new ("", ""); + CuAssertPtrNotNull (cu, test.token); + + test.session = p11_session_new (test.token); + CuAssertPtrNotNull (cu, test.session); +} + +static void +teardown (CuTest *cu) +{ + p11_session_free (test.session); + p11_token_free (test.token); + memset (&test, 0, sizeof (test)); +} + +static void +test_session_add_get (CuTest *cu) +{ + CK_ATTRIBUTE original[] = { + { CKA_LABEL, "yay", 3 }, + { CKA_VALUE, "eight", 5 }, + { CKA_INVALID } + }; + + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *check; + CK_OBJECT_HANDLE handle; + CK_BBOOL token; + + setup (cu); + + attrs = p11_attrs_dup (original); + p11_session_add_object (test.session, attrs, &handle); + + check = p11_session_get_object (test.session, handle, &token); + + CuAssertPtrEquals (cu, attrs, check); + CuAssertTrue (cu, token == CK_FALSE); + + check = p11_session_get_object (test.session, 1UL, &token); + CuAssertPtrEquals (cu, NULL, check); + + teardown (cu); +} + +static void +test_session_del (CuTest *cu) +{ + CK_ATTRIBUTE original[] = { + { CKA_LABEL, "yay", 3 }, + { CKA_VALUE, "eight", 5 }, + { CKA_INVALID } + }; + + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *check; + CK_OBJECT_HANDLE handle; + CK_BBOOL token; + CK_RV rv; + + setup (cu); + + attrs = p11_attrs_dup (original); + p11_session_add_object (test.session, attrs, &handle); + + check = p11_session_get_object (test.session, handle, &token); + CuAssertPtrEquals (cu, attrs, check); + CuAssertTrue (cu, token == CK_FALSE); + + rv = p11_session_del_object (test.session, 1UL); + CuAssertTrue (cu, rv == CKR_OBJECT_HANDLE_INVALID); + + rv = p11_session_del_object (test.session, handle); + CuAssertTrue (cu, rv == CKR_OK); + + check = p11_session_get_object (test.session, handle, &token); + CuAssertPtrEquals (cu, NULL, check); + + teardown (cu); +} + +int +main (void) +{ + CuString *output = CuStringNew (); + CuSuite* suite = CuSuiteNew (); + int ret; + + setenv ("P11_KIT_STRICT", "1", 1); + p11_debug_init (); + p11_message_quiet (); + + SUITE_ADD_TEST (suite, test_session_add_get); + SUITE_ADD_TEST (suite, test_session_del); + + CuSuiteRun (suite); + CuSuiteSummary (suite, output); + CuSuiteDetails (suite, output); + printf ("%s\n", output->buffer); + ret = suite->failCount; + CuSuiteDelete (suite); + CuStringDelete (output); + + return ret; +} diff --git a/trust/tests/test-token.c b/trust/tests/test-token.c new file mode 100644 index 0000000..1d9228a --- /dev/null +++ b/trust/tests/test-token.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "CuTest.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "attrs.h" +#include "debug.h" +#include "library.h" +#include "token.h" + +struct { + p11_token *token; +} test; + +static void +setup (CuTest *cu) +{ + test.token = p11_token_new (SRCDIR "/anchors:" SRCDIR "/files/cacert-ca.der", + SRCDIR "/files/self-server.der"); + CuAssertPtrNotNull (cu, test.token); +} + +static void +teardown (CuTest *cu) +{ + p11_token_free (test.token); + memset (&test, 0, sizeof (test)); +} + +static void +test_token_load (CuTest *cu) +{ + p11_dict *objects; + int count; + + setup (cu); + + count = p11_token_load (test.token); + CuAssertIntEquals (cu, 4, count); + + /* A certificate and trust object for each parsed object */ + objects = p11_token_objects (test.token); + CuAssertIntEquals (cu, count * 2, p11_dict_size (objects)); + + teardown (cu); +} + +int +main (void) +{ + CuString *output = CuStringNew (); + CuSuite* suite = CuSuiteNew (); + int ret; + + setenv ("P11_KIT_STRICT", "1", 1); + p11_debug_init (); + p11_message_quiet (); + + SUITE_ADD_TEST (suite, test_token_load); + + CuSuiteRun (suite); + CuSuiteSummary (suite, output); + CuSuiteDetails (suite, output); + printf ("%s\n", output->buffer); + ret = suite->failCount; + CuSuiteDelete (suite); + CuStringDelete (output); + + return ret; +} diff --git a/trust/token.c b/trust/token.c new file mode 100644 index 0000000..8a607f0 --- /dev/null +++ b/trust/token.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "config.h" + +#include "attrs.h" +#include "compat.h" +#include "debug.h" +#include "errno.h" +#include "library.h" +#include "module.h" +#include "parser.h" +#include "pkcs11.h" +#include "token.h" + +#include <sys/stat.h> +#include <sys/types.h> + +#include <dirent.h> +#include <stdlib.h> +#include <string.h> + +struct _p11_token { + p11_parser *parser; + p11_dict *objects; + const char *anchor_paths; + const char *other_paths; + const char *certificate_paths; + int loaded; +}; + +static void +on_parser_object (CK_ATTRIBUTE *attrs, + void *user_data) +{ + CK_OBJECT_HANDLE object; + CK_OBJECT_HANDLE *key; + p11_token *token = user_data; + + object = p11_module_next_id (); + + key = memdup (&object, sizeof (object)); + return_if_fail (key != NULL); + + if (!p11_dict_set (token->objects, key, attrs)) + return_if_reached (); +} + +static int +loader_load_file (p11_token *token, + const char *filename, + struct stat *sb, + int flags) +{ + int ret; + + ret = p11_parse_file (token->parser, filename, flags, + on_parser_object, token); + + return ret == P11_PARSE_SUCCESS ? 1 : 0; +} + +static int +loader_load_directory (p11_token *token, + const char *directory, + int flags) +{ + struct dirent *dp; + struct stat sb; + char *path; + int total = 0; + int ret; + DIR *dir; + + /* First we load all the modules */ + dir = opendir (directory); + if (!dir) { + p11_message ("couldn't list directory: %s: %s", + directory, strerror (errno)); + return 0; + } + + /* We're within a global mutex, so readdir is safe */ + while ((dp = readdir (dir)) != NULL) { + path = strconcat (directory, "/", dp->d_name, NULL); + return_val_if_fail (path != NULL, -1); + + if (stat (path, &sb) < 0) { + p11_message ("couldn't stat path: %s", path); + + } else if (!S_ISDIR (sb.st_mode)) { + ret = loader_load_file (token, path, &sb, flags); + return_val_if_fail (ret > 0, ret); + total += ret; + } + + free (path); + } + + closedir (dir); + return total; +} + +static int +loader_load_path (p11_token *token, + const char *path, + int flags) +{ + struct stat sb; + + if (stat (path, &sb) < 0) { + if (errno == ENOENT) { + p11_message ("trust certificate path does not exist: %s", + path); + } else { + p11_message ("cannot access trust certificate path: %s: %s", + path, strerror (errno)); + } + + return 0; + } + + if (S_ISDIR (sb.st_mode)) + return loader_load_directory (token, path, flags); + else + return loader_load_file (token, path, &sb, flags); +} + +static int +loader_load_paths (p11_token *token, + const char *paths, + int flags) +{ + const char *pos; + int total = 0; + char *path; + int ret; + + while (paths) { + pos = strchr (paths, ':'); + if (pos == NULL) { + path = strdup (paths); + paths = NULL; + } else { + path = strndup (paths, pos - paths); + paths = pos + 1; + } + + return_val_if_fail (path != NULL, -1); + + if (path[0] != '\0') { + /* We don't expect this to fail except for in strange circumstances */ + ret = loader_load_path (token, path, flags); + if (ret < 0) + return_val_if_reached (-1); + total += ret; + } + + free (path); + } + + return total; +} + +int +p11_token_load (p11_token *token) +{ + int anchors; + int other; + + if (token->loaded) + return 0; + token->loaded = 1; + + anchors = loader_load_paths (token, token->anchor_paths, P11_PARSE_FLAG_ANCHOR); + if (anchors < 0) + return anchors; + + other = loader_load_paths (token, token->other_paths, P11_PARSE_FLAG_NONE); + if (other < 0) + return other; + + return anchors + other; +} + +p11_dict * +p11_token_objects (p11_token *token) +{ + return token->objects; +} + +void +p11_token_free (p11_token *token) +{ + if (!token) + return; + + p11_dict_free (token->objects); + p11_parser_free (token->parser); + free (token); +} + +p11_token * +p11_token_new (const char *anchor_paths, + const char *other_paths) +{ + p11_token *token; + + token = calloc (1, sizeof (p11_token)); + return_val_if_fail (token != NULL, NULL); + + token->parser = p11_parser_new (); + return_val_if_fail (token->parser != NULL, NULL); + + token->objects = p11_dict_new (p11_dict_ulongptr_hash, + p11_dict_ulongptr_equal, + free, p11_attrs_free); + return_val_if_fail (token->objects != NULL, NULL); + + token->anchor_paths = anchor_paths; + token->other_paths = other_paths; + token->loaded = 0; + + return token; +} diff --git a/trust/token.h b/trust/token.h new file mode 100644 index 0000000..1152a68 --- /dev/null +++ b/trust/token.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#ifndef P11_TOKEN_H_ +#define P11_TOKEN_H_ + +#include "dict.h" + +typedef struct _p11_token p11_token; + +p11_token * p11_token_new (const char *anchor_paths, + const char *other_paths); + +void p11_token_free (p11_token *token); + +int p11_token_load (p11_token *token); + +p11_dict * p11_token_objects (p11_token *token); + +#endif /* P11_TOKEN_H_ */ |