summaryrefslogtreecommitdiff
path: root/lib/util
diff options
context:
space:
mode:
Diffstat (limited to 'lib/util')
-rw-r--r--lib/util/Makefile56
-rw-r--r--lib/util/SECerrs.h553
-rw-r--r--lib/util/base64.h43
-rw-r--r--lib/util/ciferfam.h61
-rw-r--r--lib/util/config.mk45
-rw-r--r--lib/util/derdec.c189
-rw-r--r--lib/util/derenc.c473
-rw-r--r--lib/util/dersubr.c246
-rw-r--r--lib/util/dertime.c310
-rw-r--r--lib/util/errstrs.c40
-rw-r--r--lib/util/hasht.h62
-rw-r--r--lib/util/manifest.mn86
-rw-r--r--lib/util/nssb64.h96
-rw-r--r--lib/util/nssb64d.c838
-rw-r--r--lib/util/nssb64e.c733
-rw-r--r--lib/util/nssb64t.h17
-rw-r--r--lib/util/nssilckt.h191
-rw-r--r--lib/util/nssilock.c498
-rw-r--r--lib/util/nssilock.h288
-rw-r--r--lib/util/nsslocks.h13
-rw-r--r--lib/util/nssrwlk.c447
-rw-r--r--lib/util/nssrwlk.h132
-rw-r--r--lib/util/nssrwlkt.h20
-rw-r--r--lib/util/nssutil.def272
-rw-r--r--lib/util/nssutil.h41
-rw-r--r--lib/util/nssutil.rc68
-rw-r--r--lib/util/oidstring.c114
-rw-r--r--lib/util/pkcs11.h257
-rw-r--r--lib/util/pkcs11f.h905
-rw-r--r--lib/util/pkcs11n.h464
-rw-r--r--lib/util/pkcs11p.h22
-rw-r--r--lib/util/pkcs11t.h1793
-rw-r--r--lib/util/pkcs11u.h20
-rw-r--r--lib/util/portreg.c377
-rw-r--r--lib/util/portreg.h83
-rw-r--r--lib/util/quickder.c897
-rw-r--r--lib/util/secalgid.c127
-rw-r--r--lib/util/secasn1.h294
-rw-r--r--lib/util/secasn1d.c3237
-rw-r--r--lib/util/secasn1e.c1615
-rw-r--r--lib/util/secasn1t.h270
-rw-r--r--lib/util/secasn1u.c99
-rw-r--r--lib/util/seccomon.h94
-rw-r--r--lib/util/secder.h176
-rw-r--r--lib/util/secdert.h131
-rw-r--r--lib/util/secdig.c181
-rw-r--r--lib/util/secdig.h104
-rw-r--r--lib/util/secdigt.h29
-rw-r--r--lib/util/secerr.h218
-rw-r--r--lib/util/secitem.c419
-rw-r--r--lib/util/secitem.h102
-rw-r--r--lib/util/secload.c182
-rw-r--r--lib/util/secoid.c2194
-rw-r--r--lib/util/secoid.h143
-rw-r--r--lib/util/secoidt.h486
-rw-r--r--lib/util/secplcy.c85
-rw-r--r--lib/util/secplcy.h106
-rw-r--r--lib/util/secport.c680
-rw-r--r--lib/util/secport.h252
-rw-r--r--lib/util/sectime.c161
-rw-r--r--lib/util/templates.c136
-rw-r--r--lib/util/utf8.c1800
-rw-r--r--lib/util/utilmod.c684
-rw-r--r--lib/util/utilmodt.h42
-rw-r--r--lib/util/utilpars.c1117
-rw-r--r--lib/util/utilpars.h56
-rw-r--r--lib/util/utilparst.h76
-rw-r--r--lib/util/utilrename.h162
68 files changed, 26208 insertions, 0 deletions
diff --git a/lib/util/Makefile b/lib/util/Makefile
new file mode 100644
index 000000000..0a9b74923
--- /dev/null
+++ b/lib/util/Makefile
@@ -0,0 +1,56 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+# include $(CORE_DEPTH)/coreconf/arch.mk
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+
+export:: private_export
+
+test: $(OBJDIR)/test_utf8
+
+$(OBJDIR)/test_utf8: utf8.c
+ @$(MAKE_OBJDIR)
+ $(CCF) -o $(OBJDIR)/test_utf8 -DTEST_UTF8 utf8.c $(OS_LIBS)
diff --git a/lib/util/SECerrs.h b/lib/util/SECerrs.h
new file mode 100644
index 000000000..8b6b36f22
--- /dev/null
+++ b/lib/util/SECerrs.h
@@ -0,0 +1,553 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* General security error codes */
+/* Caller must #include "secerr.h" */
+
+ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0,
+"An I/O error occurred during security authorization.")
+
+ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1,
+"security library failure.")
+
+ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2,
+"security library: received bad data.")
+
+ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3,
+"security library: output length error.")
+
+ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4,
+"security library has experienced an input length error.")
+
+ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5,
+"security library: invalid arguments.")
+
+ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6,
+"security library: invalid algorithm.")
+
+ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7,
+"security library: invalid AVA.")
+
+ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8,
+"Improperly formatted time string.")
+
+ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9,
+"security library: improperly formatted DER-encoded message.")
+
+ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10,
+"Peer's certificate has an invalid signature.")
+
+ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11,
+"Peer's Certificate has expired.")
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12,
+"Peer's Certificate has been revoked.")
+
+ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13,
+"Peer's Certificate issuer is not recognized.")
+
+ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14,
+"Peer's public key is invalid.")
+
+ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15,
+"The security password entered is incorrect.")
+
+ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16,
+"New password entered incorrectly. Please try again.")
+
+ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17,
+"security library: no nodelock.")
+
+ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18,
+"security library: bad database.")
+
+ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19,
+"security library: memory allocation failure.")
+
+ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20,
+"Peer's certificate issuer has been marked as not trusted by the user.")
+
+ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21,
+"Peer's certificate has been marked as not trusted by the user.")
+
+ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22),
+"Certificate already exists in your database.")
+
+ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23),
+"Downloaded certificate's name duplicates one already in your database.")
+
+ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24),
+"Error adding certificate to database.")
+
+ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25),
+"Error refiling the key for this certificate.")
+
+ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26),
+"The private key for this certificate cannot be found in key database")
+
+ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27),
+"This certificate is valid.")
+
+ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28),
+"This certificate is not valid.")
+
+ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29),
+"Cert Library: No Response")
+
+ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30),
+"The certificate issuer's certificate has expired. Check your system date and time.")
+
+ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31),
+"The CRL for the certificate's issuer has expired. Update it or check your system date and time.")
+
+ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32),
+"The CRL for the certificate's issuer has an invalid signature.")
+
+ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33),
+"New CRL has an invalid format.")
+
+ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34),
+"Certificate extension value is invalid.")
+
+ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35),
+"Certificate extension not found.")
+
+ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36),
+"Issuer certificate is invalid.")
+
+ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37),
+"Certificate path length constraint is invalid.")
+
+ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38),
+"Certificate usages field is invalid.")
+
+ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39),
+"**Internal ONLY module**")
+
+ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40),
+"The key does not support the requested operation.")
+
+ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41),
+"Certificate contains unknown critical extension.")
+
+ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42),
+"New CRL is not later than the current one.")
+
+ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43),
+"Not encrypted or signed: you do not yet have an email certificate.")
+
+ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44),
+"Not encrypted: you do not have certificates for each of the recipients.")
+
+ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45),
+"Cannot decrypt: you are not a recipient, or matching certificate and \
+private key not found.")
+
+ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46),
+"Cannot decrypt: key encryption algorithm does not match your certificate.")
+
+ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47),
+"Signature verification failed: no signer found, too many signers found, \
+or improper or corrupted data.")
+
+ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48),
+"Unsupported or unknown key algorithm.")
+
+ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49),
+"Cannot decrypt: encrypted using a disallowed algorithm or key size.")
+
+
+/* Fortezza Alerts */
+ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50),
+"Fortezza card has not been properly initialized. \
+Please remove it and return it to your issuer.")
+
+ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51),
+"No Fortezza cards Found")
+
+ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52),
+"No Fortezza card selected")
+
+ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53),
+"Please select a personality to get more info on")
+
+ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54),
+"Personality not found")
+
+ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55),
+"No more information on that Personality")
+
+ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56),
+"Invalid Pin")
+
+ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57),
+"Couldn't initialize Fortezza personalities.")
+/* end fortezza alerts. */
+
+ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58),
+"No KRL for this site's certificate has been found.")
+
+ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59),
+"The KRL for this site's certificate has expired.")
+
+ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60),
+"The KRL for this site's certificate has an invalid signature.")
+
+ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61),
+"The key for this site's certificate has been revoked.")
+
+ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62),
+"New KRL has an invalid format.")
+
+ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63),
+"security library: need random data.")
+
+ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64),
+"security library: no security module can perform the requested operation.")
+
+ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65),
+"The security card or token does not exist, needs to be initialized, or has been removed.")
+
+ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66),
+"security library: read-only database.")
+
+ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67),
+"No slot or token was selected.")
+
+ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68),
+"A certificate with the same nickname already exists.")
+
+ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69),
+"A key with the same nickname already exists.")
+
+ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70),
+"error while creating safe object")
+
+ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71),
+"error while creating baggage object")
+
+ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72),
+"Couldn't remove the principal")
+
+ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73),
+"Couldn't delete the privilege")
+
+ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74),
+"This principal doesn't have a certificate")
+
+ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75),
+"Required algorithm is not allowed.")
+
+ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76),
+"Error attempting to export certificates.")
+
+ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77),
+"Error attempting to import certificates.")
+
+ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78),
+"Unable to import. Decoding error. File not valid.")
+
+ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79),
+"Unable to import. Invalid MAC. Incorrect password or corrupt file.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80),
+"Unable to import. MAC algorithm not supported.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81),
+"Unable to import. Only password integrity and privacy modes supported.")
+
+ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82),
+"Unable to import. File structure is corrupt.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83),
+"Unable to import. Encryption algorithm not supported.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84),
+"Unable to import. File version not supported.")
+
+ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85),
+"Unable to import. Incorrect privacy password.")
+
+ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86),
+"Unable to import. Same nickname already exists in database.")
+
+ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87),
+"The user pressed cancel.")
+
+ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88),
+"Not imported, already in database.")
+
+ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89),
+"Message not sent.")
+
+ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90),
+"Certificate key usage inadequate for attempted operation.")
+
+ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91),
+"Certificate type not approved for application.")
+
+ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92),
+"Address in signing certificate does not match address in message headers.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93),
+"Unable to import. Error attempting to import private key.")
+
+ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94),
+"Unable to import. Error attempting to import certificate chain.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95),
+"Unable to export. Unable to locate certificate or key by nickname.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96),
+"Unable to export. Private Key could not be located and exported.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97),
+"Unable to export. Unable to write the export file.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98),
+"Unable to import. Unable to read the import file.")
+
+ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99),
+"Unable to export. Key database corrupt or deleted.")
+
+ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100),
+"Unable to generate public/private key pair.")
+
+ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101),
+"Password entered is invalid. Please pick a different one.")
+
+ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102),
+"Old password entered incorrectly. Please try again.")
+
+ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103),
+"Certificate nickname already in use.")
+
+ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104),
+"Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
+
+ER3(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, (SEC_ERROR_BASE + 105),
+"A sensitive key cannot be moved to the slot where it is needed.")
+
+ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106),
+"Invalid module name.")
+
+ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107),
+"Invalid module path/filename")
+
+ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108),
+"Unable to add module")
+
+ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109),
+"Unable to delete module")
+
+ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110),
+"New KRL is not later than the current one.")
+
+ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111),
+"New CKL has different issuer than current CKL. Delete current CKL.")
+
+ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112),
+"The Certifying Authority for this certificate is not permitted to issue a \
+certificate with this name.")
+
+ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113),
+"The key revocation list for this certificate is not yet valid.")
+
+ER3(SEC_ERROR_CRL_NOT_YET_VALID, (SEC_ERROR_BASE + 114),
+"The certificate revocation list for this certificate is not yet valid.")
+
+ER3(SEC_ERROR_UNKNOWN_CERT, (SEC_ERROR_BASE + 115),
+"The requested certificate could not be found.")
+
+ER3(SEC_ERROR_UNKNOWN_SIGNER, (SEC_ERROR_BASE + 116),
+"The signer's certificate could not be found.")
+
+ER3(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, (SEC_ERROR_BASE + 117),
+"The location for the certificate status server has invalid format.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, (SEC_ERROR_BASE + 118),
+"The OCSP response cannot be fully decoded; it is of an unknown type.")
+
+ER3(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 119),
+"The OCSP server returned unexpected/invalid HTTP data.")
+
+ER3(SEC_ERROR_OCSP_MALFORMED_REQUEST, (SEC_ERROR_BASE + 120),
+"The OCSP server found the request to be corrupted or improperly formed.")
+
+ER3(SEC_ERROR_OCSP_SERVER_ERROR, (SEC_ERROR_BASE + 121),
+"The OCSP server experienced an internal error.")
+
+ER3(SEC_ERROR_OCSP_TRY_SERVER_LATER, (SEC_ERROR_BASE + 122),
+"The OCSP server suggests trying again later.")
+
+ER3(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, (SEC_ERROR_BASE + 123),
+"The OCSP server requires a signature on this request.")
+
+ER3(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, (SEC_ERROR_BASE + 124),
+"The OCSP server has refused this request as unauthorized.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, (SEC_ERROR_BASE + 125),
+"The OCSP server returned an unrecognizable status.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_CERT, (SEC_ERROR_BASE + 126),
+"The OCSP server has no status for the certificate.")
+
+ER3(SEC_ERROR_OCSP_NOT_ENABLED, (SEC_ERROR_BASE + 127),
+"You must enable OCSP before performing this operation.")
+
+ER3(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, (SEC_ERROR_BASE + 128),
+"You must set the OCSP default responder before performing this operation.")
+
+ER3(SEC_ERROR_OCSP_MALFORMED_RESPONSE, (SEC_ERROR_BASE + 129),
+"The response from the OCSP server was corrupted or improperly formed.")
+
+ER3(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, (SEC_ERROR_BASE + 130),
+"The signer of the OCSP response is not authorized to give status for \
+this certificate.")
+
+ER3(SEC_ERROR_OCSP_FUTURE_RESPONSE, (SEC_ERROR_BASE + 131),
+"The OCSP response is not yet valid (contains a date in the future).")
+
+ER3(SEC_ERROR_OCSP_OLD_RESPONSE, (SEC_ERROR_BASE + 132),
+"The OCSP response contains out-of-date information.")
+
+ER3(SEC_ERROR_DIGEST_NOT_FOUND, (SEC_ERROR_BASE + 133),
+"The CMS or PKCS #7 Digest was not found in signed message.")
+
+ER3(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, (SEC_ERROR_BASE + 134),
+"The CMS or PKCS #7 Message type is unsupported.")
+
+ER3(SEC_ERROR_MODULE_STUCK, (SEC_ERROR_BASE + 135),
+"PKCS #11 module could not be removed because it is still in use.")
+
+ER3(SEC_ERROR_BAD_TEMPLATE, (SEC_ERROR_BASE + 136),
+"Could not decode ASN.1 data. Specified template was invalid.")
+
+ER3(SEC_ERROR_CRL_NOT_FOUND, (SEC_ERROR_BASE + 137),
+"No matching CRL was found.")
+
+ER3(SEC_ERROR_REUSED_ISSUER_AND_SERIAL, (SEC_ERROR_BASE + 138),
+"You are attempting to import a cert with the same issuer/serial as \
+an existing cert, but that is not the same cert.")
+
+ER3(SEC_ERROR_BUSY, (SEC_ERROR_BASE + 139),
+"NSS could not shutdown. Objects are still in use.")
+
+ER3(SEC_ERROR_EXTRA_INPUT, (SEC_ERROR_BASE + 140),
+"DER-encoded message contained extra unused data.")
+
+ER3(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, (SEC_ERROR_BASE + 141),
+"Unsupported elliptic curve.")
+
+ER3(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, (SEC_ERROR_BASE + 142),
+"Unsupported elliptic curve point form.")
+
+ER3(SEC_ERROR_UNRECOGNIZED_OID, (SEC_ERROR_BASE + 143),
+"Unrecognized Object Identifier.")
+
+ER3(SEC_ERROR_OCSP_INVALID_SIGNING_CERT, (SEC_ERROR_BASE + 144),
+"Invalid OCSP signing certificate in OCSP response.")
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE_CRL, (SEC_ERROR_BASE + 145),
+"Certificate is revoked in issuer's certificate revocation list.")
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE_OCSP, (SEC_ERROR_BASE + 146),
+"Issuer's OCSP responder reports certificate is revoked.")
+
+ER3(SEC_ERROR_CRL_INVALID_VERSION, (SEC_ERROR_BASE + 147),
+"Issuer's Certificate Revocation List has an unknown version number.")
+
+ER3(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 148),
+"Issuer's V1 Certificate Revocation List has a critical extension.")
+
+ER3(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 149),
+"Issuer's V2 Certificate Revocation List has an unknown critical extension.")
+
+ER3(SEC_ERROR_UNKNOWN_OBJECT_TYPE, (SEC_ERROR_BASE + 150),
+"Unknown object type specified.")
+
+ER3(SEC_ERROR_INCOMPATIBLE_PKCS11, (SEC_ERROR_BASE + 151),
+"PKCS #11 driver violates the spec in an incompatible way.")
+
+ER3(SEC_ERROR_NO_EVENT, (SEC_ERROR_BASE + 152),
+"No new slot event is available at this time.")
+
+ER3(SEC_ERROR_CRL_ALREADY_EXISTS, (SEC_ERROR_BASE + 153),
+"CRL already exists.")
+
+ER3(SEC_ERROR_NOT_INITIALIZED, (SEC_ERROR_BASE + 154),
+"NSS is not initialized.")
+
+ER3(SEC_ERROR_TOKEN_NOT_LOGGED_IN, (SEC_ERROR_BASE + 155),
+"The operation failed because the PKCS#11 token is not logged in.")
+
+ER3(SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, (SEC_ERROR_BASE + 156),
+"Configured OCSP responder's certificate is invalid.")
+
+ER3(SEC_ERROR_OCSP_BAD_SIGNATURE, (SEC_ERROR_BASE + 157),
+"OCSP response has an invalid signature.")
+
+ER3(SEC_ERROR_OUT_OF_SEARCH_LIMITS, (SEC_ERROR_BASE + 158),
+"Cert validation search is out of search limits")
+
+ER3(SEC_ERROR_INVALID_POLICY_MAPPING, (SEC_ERROR_BASE + 159),
+"Policy mapping contains anypolicy")
+
+ER3(SEC_ERROR_POLICY_VALIDATION_FAILED, (SEC_ERROR_BASE + 160),
+"Cert chain fails policy validation")
+
+ER3(SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, (SEC_ERROR_BASE + 161),
+"Unknown location type in cert AIA extension")
+
+ER3(SEC_ERROR_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 162),
+"Server returned bad HTTP response")
+
+ER3(SEC_ERROR_BAD_LDAP_RESPONSE, (SEC_ERROR_BASE + 163),
+"Server returned bad LDAP response")
+
+ER3(SEC_ERROR_FAILED_TO_ENCODE_DATA, (SEC_ERROR_BASE + 164),
+"Failed to encode data with ASN1 encoder")
+
+ER3(SEC_ERROR_BAD_INFO_ACCESS_LOCATION, (SEC_ERROR_BASE + 165),
+"Bad information access location in cert extension")
+
+ER3(SEC_ERROR_LIBPKIX_INTERNAL, (SEC_ERROR_BASE + 166),
+"Libpkix internal error occurred during cert validation.")
+
+ER3(SEC_ERROR_PKCS11_GENERAL_ERROR, (SEC_ERROR_BASE + 167),
+"A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
+
+ER3(SEC_ERROR_PKCS11_FUNCTION_FAILED, (SEC_ERROR_BASE + 168),
+"A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.")
+
+ER3(SEC_ERROR_PKCS11_DEVICE_ERROR, (SEC_ERROR_BASE + 169),
+"A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.")
+
+ER3(SEC_ERROR_BAD_INFO_ACCESS_METHOD, (SEC_ERROR_BASE + 170),
+"Unknown information access method in certificate extension.")
+
+ER3(SEC_ERROR_CRL_IMPORT_FAILED, (SEC_ERROR_BASE + 171),
+"Error attempting to import a CRL.")
+
+ER3(SEC_ERROR_EXPIRED_PASSWORD, (SEC_ERROR_BASE + 172),
+"The password expired.")
+
+ER3(SEC_ERROR_LOCKED_PASSWORD, (SEC_ERROR_BASE + 173),
+"The password is locked.")
+
+ER3(SEC_ERROR_UNKNOWN_PKCS11_ERROR, (SEC_ERROR_BASE + 174),
+"Unknown PKCS #11 error.")
+
+ER3(SEC_ERROR_BAD_CRL_DP_URL, (SEC_ERROR_BASE + 175),
+"Invalid or unsupported URL in CRL distribution point name.")
+
+ER3(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, (SEC_ERROR_BASE + 176),
+"The certificate was signed using a signature algorithm that is disabled because it is not secure.")
+
+ER3(SEC_ERROR_LEGACY_DATABASE, (SEC_ERROR_BASE + 177),
+"The certificate/key database is in an old, unsupported format.")
+
+ER3(SEC_ERROR_APPLICATION_CALLBACK_ERROR, (SEC_ERROR_BASE + 178),
+"The certificate was rejected by extra checks in the application.")
+
diff --git a/lib/util/base64.h b/lib/util/base64.h
new file mode 100644
index 000000000..1bd42ab8b
--- /dev/null
+++ b/lib/util/base64.h
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * base64.h - prototypes for base64 encoding/decoding
+ * Note: These functions are deprecated; see nssb64.h for new routines.
+ *
+ * $Id$
+ */
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+#include "utilrename.h"
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Return an PORT_Alloc'd ascii string which is the base64 encoded
+** version of the input string.
+*/
+extern char *BTOA_DataToAscii(const unsigned char *data, unsigned int len);
+
+/*
+** Return an PORT_Alloc'd string which is the base64 decoded version
+** of the input string; set *lenp to the length of the returned data.
+*/
+extern unsigned char *ATOB_AsciiToData(const char *string, unsigned int *lenp);
+
+/*
+** Convert from ascii to binary encoding of an item.
+*/
+extern SECStatus ATOB_ConvertAsciiToItem(SECItem *binary_item, const char *ascii);
+
+/*
+** Convert from binary encoding of an item to ascii.
+*/
+extern char *BTOA_ConvertItemToAscii(SECItem *binary_item);
+
+SEC_END_PROTOS
+
+#endif /* _BASE64_H_ */
diff --git a/lib/util/ciferfam.h b/lib/util/ciferfam.h
new file mode 100644
index 000000000..8d288a926
--- /dev/null
+++ b/lib/util/ciferfam.h
@@ -0,0 +1,61 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * ciferfam.h - cipher familie IDs used for configuring ciphers for export
+ * control
+ *
+ * $Id$
+ */
+
+#ifndef _CIFERFAM_H_
+#define _CIFERFAM_H_
+
+#include "utilrename.h"
+/* Cipher Suite "Families" */
+#define CIPHER_FAMILY_PKCS12 "PKCS12"
+#define CIPHER_FAMILY_SMIME "SMIME"
+#define CIPHER_FAMILY_SSL2 "SSLv2"
+#define CIPHER_FAMILY_SSL3 "SSLv3"
+#define CIPHER_FAMILY_SSL "SSL"
+#define CIPHER_FAMILY_ALL ""
+#define CIPHER_FAMILY_UNKNOWN "UNKNOWN"
+
+#define CIPHER_FAMILYID_MASK 0xFFFF0000L
+#define CIPHER_FAMILYID_SSL 0x00000000L
+#define CIPHER_FAMILYID_SMIME 0x00010000L
+#define CIPHER_FAMILYID_PKCS12 0x00020000L
+
+/* SMIME "Cipher Suites" */
+/*
+ * Note that it is assumed that the cipher number itself can be used
+ * as a bit position in a mask, and that mask is currently 32 bits wide.
+ * So, if you want to add a cipher that is greater than 0037, secmime.c
+ * needs to be made smarter at the same time.
+ */
+#define SMIME_RC2_CBC_40 (CIPHER_FAMILYID_SMIME | 0001)
+#define SMIME_RC2_CBC_64 (CIPHER_FAMILYID_SMIME | 0002)
+#define SMIME_RC2_CBC_128 (CIPHER_FAMILYID_SMIME | 0003)
+#define SMIME_DES_CBC_56 (CIPHER_FAMILYID_SMIME | 0011)
+#define SMIME_DES_EDE3_168 (CIPHER_FAMILYID_SMIME | 0012)
+#define SMIME_AES_CBC_128 (CIPHER_FAMILYID_SMIME | 0013)
+#define SMIME_AES_CBC_256 (CIPHER_FAMILYID_SMIME | 0014)
+#define SMIME_RC5PAD_64_16_40 (CIPHER_FAMILYID_SMIME | 0021)
+#define SMIME_RC5PAD_64_16_64 (CIPHER_FAMILYID_SMIME | 0022)
+#define SMIME_RC5PAD_64_16_128 (CIPHER_FAMILYID_SMIME | 0023)
+#define SMIME_FORTEZZA (CIPHER_FAMILYID_SMIME | 0031)
+
+/* PKCS12 "Cipher Suites" */
+
+#define PKCS12_RC2_CBC_40 (CIPHER_FAMILYID_PKCS12 | 0001)
+#define PKCS12_RC2_CBC_128 (CIPHER_FAMILYID_PKCS12 | 0002)
+#define PKCS12_RC4_40 (CIPHER_FAMILYID_PKCS12 | 0011)
+#define PKCS12_RC4_128 (CIPHER_FAMILYID_PKCS12 | 0012)
+#define PKCS12_DES_56 (CIPHER_FAMILYID_PKCS12 | 0021)
+#define PKCS12_DES_EDE3_168 (CIPHER_FAMILYID_PKCS12 | 0022)
+
+/* SMIME version numbers are negative, to avoid colliding with SSL versions */
+#define SMIME_LIBRARY_VERSION_1_0 -0x0100
+
+#endif /* _CIFERFAM_H_ */
diff --git a/lib/util/config.mk b/lib/util/config.mk
new file mode 100644
index 000000000..a3e720218
--- /dev/null
+++ b/lib/util/config.mk
@@ -0,0 +1,45 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# can't do this in manifest.mn because OS_TARGET isn't defined there.
+ifeq (,$(filter-out WIN%,$(OS_TARGET)))
+
+# don't want the 32 in the shared library name
+SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
+IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX)
+
+RES = $(OBJDIR)/$(LIBRARY_NAME).res
+RESNAME = $(LIBRARY_NAME).rc
+
+ifdef NS_USE_GCC
+EXTRA_SHARED_LIBS += \
+ -L$(DIST)/lib \
+ -L$(NSPR_LIB_DIR) \
+ -lplc4 \
+ -lplds4 \
+ -lnspr4\
+ $(NULL)
+else # ! NS_USE_GCC
+EXTRA_SHARED_LIBS += \
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \
+ $(NULL)
+endif # NS_USE_GCC
+
+else
+
+# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
+# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
+EXTRA_SHARED_LIBS += \
+ -L$(DIST)/lib \
+ -L$(NSPR_LIB_DIR) \
+ -lplc4 \
+ -lplds4 \
+ -lnspr4 \
+ $(NULL)
+
+endif
+
diff --git a/lib/util/derdec.c b/lib/util/derdec.c
new file mode 100644
index 000000000..c62191487
--- /dev/null
+++ b/lib/util/derdec.c
@@ -0,0 +1,189 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secder.h"
+#include "secerr.h"
+
+static PRUint32
+der_indefinite_length(unsigned char *buf, unsigned char *end)
+{
+ PRUint32 len, ret, dataLen;
+ unsigned char tag, lenCode;
+ int dataLenLen;
+
+ len = 0;
+ while ( 1 ) {
+ if ((buf + 2) > end) {
+ return(0);
+ }
+
+ tag = *buf++;
+ lenCode = *buf++;
+ len += 2;
+
+ if ( ( tag == 0 ) && ( lenCode == 0 ) ) {
+ return(len);
+ }
+
+ if ( lenCode == 0x80 ) { /* indefinite length */
+ ret = der_indefinite_length(buf, end); /* recurse to find length */
+ if (ret == 0)
+ return 0;
+ len += ret;
+ buf += ret;
+ } else { /* definite length */
+ if (lenCode & 0x80) {
+ /* Length of data is in multibyte format */
+ dataLenLen = lenCode & 0x7f;
+ switch (dataLenLen) {
+ case 1:
+ dataLen = buf[0];
+ break;
+ case 2:
+ dataLen = (buf[0]<<8)|buf[1];
+ break;
+ case 3:
+ dataLen = ((unsigned long)buf[0]<<16)|(buf[1]<<8)|buf[2];
+ break;
+ case 4:
+ dataLen = ((unsigned long)buf[0]<<24)|
+ ((unsigned long)buf[1]<<16)|(buf[2]<<8)|buf[3];
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ } else {
+ /* Length of data is in single byte */
+ dataLen = lenCode;
+ dataLenLen = 0;
+ }
+
+ /* skip this item */
+ buf = buf + dataLenLen + dataLen;
+ len = len + dataLenLen + dataLen;
+ }
+ }
+}
+
+/*
+** Capture the next thing in the buffer.
+** Returns the length of the header and the length of the contents.
+*/
+static SECStatus
+der_capture(unsigned char *buf, unsigned char *end,
+ int *header_len_p, PRUint32 *contents_len_p)
+{
+ unsigned char *bp;
+ unsigned char whole_tag;
+ PRUint32 contents_len;
+ int tag_number;
+
+ if ((buf + 2) > end) {
+ *header_len_p = 0;
+ *contents_len_p = 0;
+ if (buf == end)
+ return SECSuccess;
+ return SECFailure;
+ }
+
+ bp = buf;
+
+ /* Get tag and verify that it is ok. */
+ whole_tag = *bp++;
+ tag_number = whole_tag & DER_TAGNUM_MASK;
+
+ /*
+ * XXX This code does not (yet) handle the high-tag-number form!
+ */
+ if (tag_number == DER_HIGH_TAG_NUMBER) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
+ /* Check that the universal tag number is one we implement. */
+ switch (tag_number) {
+ case DER_BOOLEAN:
+ case DER_INTEGER:
+ case DER_BIT_STRING:
+ case DER_OCTET_STRING:
+ case DER_NULL:
+ case DER_OBJECT_ID:
+ case DER_SEQUENCE:
+ case DER_SET:
+ case DER_PRINTABLE_STRING:
+ case DER_T61_STRING:
+ case DER_IA5_STRING:
+ case DER_VISIBLE_STRING:
+ case DER_UTC_TIME:
+ case 0: /* end-of-contents tag */
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ }
+
+ /*
+ * Get first byte of length code (might contain entire length, might not).
+ */
+ contents_len = *bp++;
+
+ /*
+ * If the high bit is set, then the length is in multibyte format,
+ * or the thing has an indefinite-length.
+ */
+ if (contents_len & 0x80) {
+ int bytes_of_encoded_len;
+
+ bytes_of_encoded_len = contents_len & 0x7f;
+ contents_len = 0;
+
+ switch (bytes_of_encoded_len) {
+ case 4:
+ contents_len |= *bp++;
+ contents_len <<= 8;
+ /* fallthru */
+ case 3:
+ contents_len |= *bp++;
+ contents_len <<= 8;
+ /* fallthru */
+ case 2:
+ contents_len |= *bp++;
+ contents_len <<= 8;
+ /* fallthru */
+ case 1:
+ contents_len |= *bp++;
+ break;
+
+ case 0:
+ contents_len = der_indefinite_length (bp, end);
+ if (contents_len)
+ break;
+ /* fallthru */
+ default:
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ }
+
+ if ((bp + contents_len) > end) {
+ /* Ran past end of buffer */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ *header_len_p = bp - buf;
+ *contents_len_p = contents_len;
+
+ return SECSuccess;
+}
+
+SECStatus
+DER_Lengths(SECItem *item, int *header_len_p, PRUint32 *contents_len_p)
+{
+ return(der_capture(item->data, &item->data[item->len], header_len_p,
+ contents_len_p));
+}
diff --git a/lib/util/derenc.c b/lib/util/derenc.c
new file mode 100644
index 000000000..459878b3f
--- /dev/null
+++ b/lib/util/derenc.c
@@ -0,0 +1,473 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secder.h"
+#include "secerr.h"
+
+#if 0
+/*
+ * Generic templates for individual/simple items.
+ */
+
+DERTemplate SECAnyTemplate[] = {
+ { DER_ANY,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECBitStringTemplate[] = {
+ { DER_BIT_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECBooleanTemplate[] = {
+ { DER_BOOLEAN,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECIA5StringTemplate[] = {
+ { DER_IA5_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECIntegerTemplate[] = {
+ { DER_INTEGER,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECNullTemplate[] = {
+ { DER_NULL,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECObjectIDTemplate[] = {
+ { DER_OBJECT_ID,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECOctetStringTemplate[] = {
+ { DER_OCTET_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECPrintableStringTemplate[] = {
+ { DER_PRINTABLE_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECT61StringTemplate[] = {
+ { DER_T61_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECUTCTimeTemplate[] = {
+ { DER_UTC_TIME,
+ 0, NULL, sizeof(SECItem) }
+};
+
+#endif
+
+static int
+header_length(DERTemplate *dtemplate, PRUint32 contents_len)
+{
+ PRUint32 len;
+ unsigned long encode_kind, under_kind;
+ PRBool explicit, optional, universal;
+
+ encode_kind = dtemplate->kind;
+
+ explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ PORT_Assert (!(explicit && universal)); /* bad templates */
+
+ if (encode_kind & DER_POINTER) {
+ if (dtemplate->sub != NULL) {
+ under_kind = dtemplate->sub->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ } else if (universal) {
+ under_kind = encode_kind & ~DER_POINTER;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+ } else if (encode_kind & DER_INLINE) {
+ PORT_Assert (dtemplate->sub != NULL);
+ under_kind = dtemplate->sub->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ } else if (universal) {
+ under_kind = encode_kind;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+
+ /* This is only used in decoding; it plays no part in encoding. */
+ if (under_kind & DER_DERPTR)
+ return 0;
+
+ /* No header at all for an "empty" optional. */
+ if ((contents_len == 0) && optional)
+ return 0;
+
+ /* And no header for a full DER_ANY. */
+ if (encode_kind & DER_ANY)
+ return 0;
+
+ /*
+ * The common case: one octet for identifier and as many octets
+ * as necessary to hold the content length.
+ */
+ len = 1 + DER_LengthLength(contents_len);
+
+ /* Account for the explicit wrapper, if necessary. */
+ if (explicit) {
+#if 0 /*
+ * Well, I was trying to do something useful, but these
+ * assertions are too restrictive on valid templates.
+ * I wanted to make sure that the top-level "kind" of
+ * a template does not also specify DER_EXPLICIT, which
+ * should only modify a component field. Maybe later
+ * I can figure out a better way to detect such a problem,
+ * but for now I must remove these checks altogether.
+ */
+ /*
+ * This modifier applies only to components of a set or sequence;
+ * it should never be used on a set/sequence itself -- confirm.
+ */
+ PORT_Assert (under_kind != DER_SEQUENCE);
+ PORT_Assert (under_kind != DER_SET);
+#endif
+
+ len += 1 + DER_LengthLength(len + contents_len);
+ }
+
+ return len;
+}
+
+
+static PRUint32
+contents_length(DERTemplate *dtemplate, void *src)
+{
+ PRUint32 len;
+ unsigned long encode_kind, under_kind;
+ PRBool universal;
+
+
+ PORT_Assert (src != NULL);
+
+ encode_kind = dtemplate->kind;
+
+ universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~DER_OPTIONAL;
+
+ if (encode_kind & DER_POINTER) {
+ src = *(void **)src;
+ if (src == NULL) {
+ return 0;
+ }
+ if (dtemplate->sub != NULL) {
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind & ~DER_POINTER;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+ } else if (encode_kind & DER_INLINE) {
+ PORT_Assert (dtemplate->sub != NULL);
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+
+ /* Having any of these bits is not expected here... */
+ PORT_Assert ((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL
+ | DER_POINTER | DER_SKIP)) == 0);
+
+ /* This is only used in decoding; it plays no part in encoding. */
+ if (under_kind & DER_DERPTR)
+ return 0;
+
+ if (under_kind & DER_INDEFINITE) {
+ PRUint32 sub_len;
+ void **indp = *(void ***)src;
+
+ if (indp == NULL)
+ return 0;
+
+ len = 0;
+ under_kind &= ~DER_INDEFINITE;
+
+ if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
+ DERTemplate *tmpt = dtemplate->sub;
+ PORT_Assert (tmpt != NULL);
+
+ for (; *indp != NULL; indp++) {
+ void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
+ sub_len = contents_length (tmpt, sub_src);
+ len += sub_len + header_length (tmpt, sub_len);
+ }
+ } else {
+ /*
+ * XXX Lisa is not sure this code (for handling, for example,
+ * DER_INDEFINITE | DER_OCTET_STRING) is right.
+ */
+ for (; *indp != NULL; indp++) {
+ SECItem *item = (SECItem *)(*indp);
+ sub_len = item->len;
+ if (under_kind == DER_BIT_STRING) {
+ sub_len = (sub_len + 7) >> 3;
+ /* bit string contents involve an extra octet */
+ if (sub_len)
+ sub_len++;
+ }
+ if (under_kind != DER_ANY)
+ len += 1 + DER_LengthLength (sub_len);
+ }
+ }
+
+ return len;
+ }
+
+ switch (under_kind) {
+ case DER_SEQUENCE:
+ case DER_SET:
+ {
+ DERTemplate *tmpt;
+ void *sub_src;
+ PRUint32 sub_len;
+
+ len = 0;
+ for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
+ sub_src = (void *)((char *)src + tmpt->offset);
+ sub_len = contents_length (tmpt, sub_src);
+ len += sub_len + header_length (tmpt, sub_len);
+ }
+ }
+ break;
+
+ case DER_BIT_STRING:
+ len = (((SECItem *)src)->len + 7) >> 3;
+ /* bit string contents involve an extra octet */
+ if (len)
+ len++;
+ break;
+
+ default:
+ len = ((SECItem *)src)->len;
+ break;
+ }
+
+ return len;
+}
+
+
+static unsigned char *
+der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
+{
+ int header_len;
+ PRUint32 contents_len;
+ unsigned long encode_kind, under_kind;
+ PRBool explicit, optional, universal;
+
+
+ /*
+ * First figure out how long the encoding will be. Do this by
+ * traversing the template from top to bottom and accumulating
+ * the length of each leaf item.
+ */
+ contents_len = contents_length (dtemplate, src);
+ header_len = header_length (dtemplate, contents_len);
+
+ /*
+ * Enough smarts was involved already, so that if both the
+ * header and the contents have a length of zero, then we
+ * are not doing any encoding for this element.
+ */
+ if (header_len == 0 && contents_len == 0)
+ return buf;
+
+ encode_kind = dtemplate->kind;
+
+ explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~DER_OPTIONAL;
+ universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ if (encode_kind & DER_POINTER) {
+ if (contents_len) {
+ src = *(void **)src;
+ PORT_Assert (src != NULL);
+ }
+ if (dtemplate->sub != NULL) {
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind & ~DER_POINTER;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+ } else if (encode_kind & DER_INLINE) {
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+
+ if (explicit) {
+ buf = DER_StoreHeader (buf, encode_kind,
+ (1 + DER_LengthLength(contents_len)
+ + contents_len));
+ encode_kind = under_kind;
+ }
+
+ if ((encode_kind & DER_ANY) == 0) { /* DER_ANY already contains header */
+ buf = DER_StoreHeader (buf, encode_kind, contents_len);
+ }
+
+ /* If no real contents to encode, then we are done. */
+ if (contents_len == 0)
+ return buf;
+
+ if (under_kind & DER_INDEFINITE) {
+ void **indp;
+
+ indp = *(void ***)src;
+ PORT_Assert (indp != NULL);
+
+ under_kind &= ~DER_INDEFINITE;
+ if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
+ DERTemplate *tmpt = dtemplate->sub;
+ PORT_Assert (tmpt != NULL);
+ for (; *indp != NULL; indp++) {
+ void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
+ buf = der_encode (buf, tmpt, sub_src);
+ }
+ } else {
+ for (; *indp != NULL; indp++) {
+ SECItem *item;
+ int sub_len;
+
+ item = (SECItem *)(*indp);
+ sub_len = item->len;
+ if (under_kind == DER_BIT_STRING) {
+ if (sub_len) {
+ int rem;
+
+ sub_len = (sub_len + 7) >> 3;
+ buf = DER_StoreHeader (buf, under_kind, sub_len + 1);
+ rem = (sub_len << 3) - item->len;
+ *buf++ = rem; /* remaining bits */
+ } else {
+ buf = DER_StoreHeader (buf, under_kind, 0);
+ }
+ } else if (under_kind != DER_ANY) {
+ buf = DER_StoreHeader (buf, under_kind, sub_len);
+ }
+ PORT_Memcpy (buf, item->data, sub_len);
+ buf += sub_len;
+ }
+ }
+ return buf;
+ }
+
+ switch (under_kind) {
+ case DER_SEQUENCE:
+ case DER_SET:
+ {
+ DERTemplate *tmpt;
+ void *sub_src;
+
+ for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
+ sub_src = (void *)((char *)src + tmpt->offset);
+ buf = der_encode (buf, tmpt, sub_src);
+ }
+ }
+ break;
+
+ case DER_BIT_STRING:
+ {
+ SECItem *item;
+ int rem;
+
+ /*
+ * The contents length includes our extra octet; subtract
+ * it off so we just have the real string length there.
+ */
+ contents_len--;
+ item = (SECItem *)src;
+ PORT_Assert (contents_len == ((item->len + 7) >> 3));
+ rem = (contents_len << 3) - item->len;
+ *buf++ = rem; /* remaining bits */
+ PORT_Memcpy (buf, item->data, contents_len);
+ buf += contents_len;
+ }
+ break;
+
+ default:
+ {
+ SECItem *item;
+
+ item = (SECItem *)src;
+ PORT_Assert (contents_len == item->len);
+ PORT_Memcpy (buf, item->data, contents_len);
+ buf += contents_len;
+ }
+ break;
+ }
+
+ return buf;
+}
+
+
+SECStatus
+DER_Encode(PRArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
+{
+ unsigned int contents_len, header_len;
+
+ src = (void **)((char *)src + dtemplate->offset);
+
+ /*
+ * First figure out how long the encoding will be. Do this by
+ * traversing the template from top to bottom and accumulating
+ * the length of each leaf item.
+ */
+ contents_len = contents_length (dtemplate, src);
+ header_len = header_length (dtemplate, contents_len);
+
+ dest->len = contents_len + header_len;
+
+ /* Allocate storage to hold the encoding */
+ dest->data = (unsigned char*) PORT_ArenaAlloc(arena, dest->len);
+ if (dest->data == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+
+ /* Now encode into the buffer */
+ (void) der_encode (dest->data, dtemplate, src);
+
+ return SECSuccess;
+}
diff --git a/lib/util/dersubr.c b/lib/util/dersubr.c
new file mode 100644
index 000000000..103613935
--- /dev/null
+++ b/lib/util/dersubr.c
@@ -0,0 +1,246 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secder.h"
+#include <limits.h>
+#include "secerr.h"
+
+int
+DER_LengthLength(PRUint32 len)
+{
+ if (len > 127) {
+ if (len > 255) {
+ if (len > 65535L) {
+ if (len > 16777215L) {
+ return 5;
+ } else {
+ return 4;
+ }
+ } else {
+ return 3;
+ }
+ } else {
+ return 2;
+ }
+ } else {
+ return 1;
+ }
+}
+
+unsigned char *
+DER_StoreHeader(unsigned char *buf, unsigned int code, PRUint32 len)
+{
+ unsigned char b[4];
+
+ b[0] = (unsigned char)(len >> 24);
+ b[1] = (unsigned char)(len >> 16);
+ b[2] = (unsigned char)(len >> 8);
+ b[3] = (unsigned char)len;
+ if ((code & DER_TAGNUM_MASK) == DER_SET
+ || (code & DER_TAGNUM_MASK) == DER_SEQUENCE)
+ code |= DER_CONSTRUCTED;
+ *buf++ = code;
+ if (len > 127) {
+ if (len > 255) {
+ if (len > 65535) {
+ if (len > 16777215) {
+ *buf++ = 0x84;
+ *buf++ = b[0];
+ *buf++ = b[1];
+ *buf++ = b[2];
+ *buf++ = b[3];
+ } else {
+ *buf++ = 0x83;
+ *buf++ = b[1];
+ *buf++ = b[2];
+ *buf++ = b[3];
+ }
+ } else {
+ *buf++ = 0x82;
+ *buf++ = b[2];
+ *buf++ = b[3];
+ }
+ } else {
+ *buf++ = 0x81;
+ *buf++ = b[3];
+ }
+ } else {
+ *buf++ = b[3];
+ }
+ return buf;
+}
+
+/*
+ * XXX This should be rewritten, generalized, to take a long instead
+ * of a PRInt32.
+ */
+SECStatus
+DER_SetInteger(PRArenaPool *arena, SECItem *it, PRInt32 i)
+{
+ unsigned char bb[4];
+ unsigned len;
+
+ bb[0] = (unsigned char) (i >> 24);
+ bb[1] = (unsigned char) (i >> 16);
+ bb[2] = (unsigned char) (i >> 8);
+ bb[3] = (unsigned char) (i);
+
+ /*
+ ** Small integers are encoded in a single byte. Larger integers
+ ** require progressively more space.
+ */
+ if (i < -128) {
+ if (i < -32768L) {
+ if (i < -8388608L) {
+ len = 4;
+ } else {
+ len = 3;
+ }
+ } else {
+ len = 2;
+ }
+ } else if (i > 127) {
+ if (i > 32767L) {
+ if (i > 8388607L) {
+ len = 4;
+ } else {
+ len = 3;
+ }
+ } else {
+ len = 2;
+ }
+ } else {
+ len = 1;
+ }
+ it->data = (unsigned char*) PORT_ArenaAlloc(arena, len);
+ if (!it->data) {
+ return SECFailure;
+ }
+ it->len = len;
+ PORT_Memcpy(it->data, bb + (4 - len), len);
+ return SECSuccess;
+}
+
+/*
+ * XXX This should be rewritten, generalized, to take an unsigned long instead
+ * of a PRUint32.
+ */
+SECStatus
+DER_SetUInteger(PRArenaPool *arena, SECItem *it, PRUint32 ui)
+{
+ unsigned char bb[5];
+ int len;
+
+ bb[0] = 0;
+ bb[1] = (unsigned char) (ui >> 24);
+ bb[2] = (unsigned char) (ui >> 16);
+ bb[3] = (unsigned char) (ui >> 8);
+ bb[4] = (unsigned char) (ui);
+
+ /*
+ ** Small integers are encoded in a single byte. Larger integers
+ ** require progressively more space.
+ */
+ if (ui > 0x7f) {
+ if (ui > 0x7fff) {
+ if (ui > 0x7fffffL) {
+ if (ui >= 0x80000000L) {
+ len = 5;
+ } else {
+ len = 4;
+ }
+ } else {
+ len = 3;
+ }
+ } else {
+ len = 2;
+ }
+ } else {
+ len = 1;
+ }
+
+ it->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
+ if (it->data == NULL) {
+ return SECFailure;
+ }
+
+ it->len = len;
+ PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len);
+
+ return SECSuccess;
+}
+
+/*
+** Convert a der encoded *signed* integer into a machine integral value.
+** If an underflow/overflow occurs, sets error code and returns min/max.
+*/
+long
+DER_GetInteger(SECItem *it)
+{
+ long ival = 0;
+ unsigned len = it->len;
+ unsigned char *cp = it->data;
+ unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1);
+ unsigned long ofloinit;
+
+ PORT_Assert(len);
+ if (!len) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return 0;
+ }
+
+ if (*cp & 0x80)
+ ival = -1L;
+ ofloinit = ival & overflow;
+
+ while (len) {
+ if ((ival & overflow) != ofloinit) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ if (ival < 0) {
+ return LONG_MIN;
+ }
+ return LONG_MAX;
+ }
+ ival = ival << 8;
+ ival |= *cp++;
+ --len;
+ }
+ return ival;
+}
+
+/*
+** Convert a der encoded *unsigned* integer into a machine integral value.
+** If an overflow occurs, sets error code and returns max.
+*/
+unsigned long
+DER_GetUInteger(SECItem *it)
+{
+ unsigned long ival = 0;
+ unsigned len = it->len;
+ unsigned char *cp = it->data;
+ unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8);
+
+ PORT_Assert(len);
+ if (!len) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ return 0;
+ }
+
+ /* Cannot put a negative value into an unsigned container. */
+ if (*cp & 0x80) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return 0;
+ }
+
+ while (len) {
+ if (ival & overflow) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return ULONG_MAX;
+ }
+ ival = ival << 8;
+ ival |= *cp++;
+ --len;
+ }
+ return ival;
+}
diff --git a/lib/util/dertime.c b/lib/util/dertime.c
new file mode 100644
index 000000000..53e97ab55
--- /dev/null
+++ b/lib/util/dertime.c
@@ -0,0 +1,310 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prtypes.h"
+#include "prtime.h"
+#include "secder.h"
+#include "prlong.h"
+#include "secerr.h"
+
+#define HIDIGIT(v) (((v) / 10) + '0')
+#define LODIGIT(v) (((v) % 10) + '0')
+
+#define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
+#define CAPTURE(var,p,label) \
+{ \
+ if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
+ (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
+ p += 2; \
+}
+
+static const PRTime January1st1 = (PRTime) LL_INIT(0xff234001U, 0x00d44000U);
+static const PRTime January1st1950 = (PRTime) LL_INIT(0xfffdc1f8U, 0x793da000U);
+static const PRTime January1st2050 = LL_INIT(0x0008f81e, 0x1b098000);
+static const PRTime January1st10000 = LL_INIT(0x0384440c, 0xcc736000);
+
+/* gmttime must contains UTC time in micro-seconds unit */
+SECStatus
+DER_TimeToUTCTimeArena(PRArenaPool* arenaOpt, SECItem *dst, int64 gmttime)
+{
+ PRExplodedTime printableTime;
+ unsigned char *d;
+
+ if ( (gmttime < January1st1950) || (gmttime >= January1st2050) ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ dst->len = 13;
+ if (arenaOpt) {
+ dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len);
+ } else {
+ dst->data = d = (unsigned char*) PORT_Alloc(dst->len);
+ }
+ dst->type = siUTCTime;
+ if (!d) {
+ return SECFailure;
+ }
+
+ /* Convert an int64 time to a printable format. */
+ PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
+
+ /* The month in UTC time is base one */
+ printableTime.tm_month++;
+
+ /* remove the century since it's added to the tm_year by the
+ PR_ExplodeTime routine, but is not needed for UTC time */
+ printableTime.tm_year %= 100;
+
+ d[0] = HIDIGIT(printableTime.tm_year);
+ d[1] = LODIGIT(printableTime.tm_year);
+ d[2] = HIDIGIT(printableTime.tm_month);
+ d[3] = LODIGIT(printableTime.tm_month);
+ d[4] = HIDIGIT(printableTime.tm_mday);
+ d[5] = LODIGIT(printableTime.tm_mday);
+ d[6] = HIDIGIT(printableTime.tm_hour);
+ d[7] = LODIGIT(printableTime.tm_hour);
+ d[8] = HIDIGIT(printableTime.tm_min);
+ d[9] = LODIGIT(printableTime.tm_min);
+ d[10] = HIDIGIT(printableTime.tm_sec);
+ d[11] = LODIGIT(printableTime.tm_sec);
+ d[12] = 'Z';
+ return SECSuccess;
+}
+
+SECStatus
+DER_TimeToUTCTime(SECItem *dst, int64 gmttime)
+{
+ return DER_TimeToUTCTimeArena(NULL, dst, gmttime);
+}
+
+static SECStatus /* forward */
+der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
+ const char **endptr);
+
+#define GEN_STRING 2 /* TimeString is a GeneralizedTime */
+#define UTC_STRING 0 /* TimeString is a UTCTime */
+
+/* The caller of DER_AsciiToItem MUST ENSURE that either
+** a) "string" points to a null-terminated ASCII string, or
+** b) "string" points to a buffer containing a valid UTCTime,
+** whether null terminated or not, or
+** c) "string" contains at least 19 characters, with or without null char.
+** otherwise, this function may UMR and/or crash.
+** It suffices to ensure that the input "string" is at least 17 bytes long.
+*/
+SECStatus
+DER_AsciiToTime(int64 *dst, const char *string)
+{
+ return der_TimeStringToTime(dst, string, UTC_STRING, NULL);
+}
+
+SECStatus
+DER_UTCTimeToTime(int64 *dst, const SECItem *time)
+{
+ /* Minimum valid UTCTime is yymmddhhmmZ which is 11 bytes.
+ ** Maximum valid UTCTime is yymmddhhmmss+0000 which is 17 bytes.
+ ** 20 should be large enough for all valid encoded times.
+ */
+ unsigned int i;
+ char localBuf[20];
+ const char *end = NULL;
+ SECStatus rv;
+
+ if (!time || !time->data || time->len < 11 || time->len > 17) {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+
+ for (i = 0; i < time->len; i++) {
+ if (time->data[i] == '\0') {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+ localBuf[i] = time->data[i];
+ }
+ localBuf[i] = '\0';
+
+ rv = der_TimeStringToTime(dst, localBuf, UTC_STRING, &end);
+ if (rv == SECSuccess && *end != '\0') {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+ return rv;
+}
+
+/*
+ gmttime must contains UTC time in micro-seconds unit.
+ Note: the caller should make sure that Generalized time
+ should only be used for certifiate validities after the
+ year 2049. Otherwise, UTC time should be used. This routine
+ does not check this case, since it can be used to encode
+ certificate extension, which does not have this restriction.
+ */
+SECStatus
+DER_TimeToGeneralizedTimeArena(PRArenaPool* arenaOpt, SECItem *dst, int64 gmttime)
+{
+ PRExplodedTime printableTime;
+ unsigned char *d;
+
+ if ( (gmttime<January1st1) || (gmttime>=January1st10000) ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ dst->len = 15;
+ if (arenaOpt) {
+ dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len);
+ } else {
+ dst->data = d = (unsigned char*) PORT_Alloc(dst->len);
+ }
+ dst->type = siGeneralizedTime;
+ if (!d) {
+ return SECFailure;
+ }
+
+ /* Convert an int64 time to a printable format. */
+ PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
+
+ /* The month in Generalized time is base one */
+ printableTime.tm_month++;
+
+ d[0] = (printableTime.tm_year /1000) + '0';
+ d[1] = ((printableTime.tm_year % 1000) / 100) + '0';
+ d[2] = ((printableTime.tm_year % 100) / 10) + '0';
+ d[3] = (printableTime.tm_year % 10) + '0';
+ d[4] = HIDIGIT(printableTime.tm_month);
+ d[5] = LODIGIT(printableTime.tm_month);
+ d[6] = HIDIGIT(printableTime.tm_mday);
+ d[7] = LODIGIT(printableTime.tm_mday);
+ d[8] = HIDIGIT(printableTime.tm_hour);
+ d[9] = LODIGIT(printableTime.tm_hour);
+ d[10] = HIDIGIT(printableTime.tm_min);
+ d[11] = LODIGIT(printableTime.tm_min);
+ d[12] = HIDIGIT(printableTime.tm_sec);
+ d[13] = LODIGIT(printableTime.tm_sec);
+ d[14] = 'Z';
+ return SECSuccess;
+}
+
+SECStatus
+DER_TimeToGeneralizedTime(SECItem *dst, int64 gmttime)
+{
+ return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime);
+}
+
+
+SECStatus
+DER_GeneralizedTimeToTime(int64 *dst, const SECItem *time)
+{
+ /* Minimum valid GeneralizedTime is ccyymmddhhmmZ which is 13 bytes.
+ ** Maximum valid GeneralizedTime is ccyymmddhhmmss+0000 which is 19 bytes.
+ ** 20 should be large enough for all valid encoded times.
+ */
+ unsigned int i;
+ char localBuf[20];
+ const char *end = NULL;
+ SECStatus rv;
+
+ if (!time || !time->data || time->len < 13 || time->len > 19) {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+
+ for (i = 0; i < time->len; i++) {
+ if (time->data[i] == '\0') {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+ localBuf[i] = time->data[i];
+ }
+ localBuf[i] = '\0';
+
+ rv = der_TimeStringToTime(dst, localBuf, GEN_STRING, &end);
+ if (rv == SECSuccess && *end != '\0') {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+ return rv;
+}
+
+static SECStatus
+der_TimeStringToTime(PRTime *dst, const char *string, int generalized,
+ const char **endptr)
+{
+ PRExplodedTime genTime;
+ long hourOff = 0, minOff = 0;
+ uint16 century;
+ char signum;
+
+ if (string == NULL || dst == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Verify time is formatted properly and capture information */
+ memset(&genTime, 0, sizeof genTime);
+
+ if (generalized == UTC_STRING) {
+ CAPTURE(genTime.tm_year, string, loser);
+ century = (genTime.tm_year < 50) ? 20 : 19;
+ } else {
+ CAPTURE(century, string, loser);
+ CAPTURE(genTime.tm_year, string, loser);
+ }
+ genTime.tm_year += century * 100;
+
+ CAPTURE(genTime.tm_month, string, loser);
+ if ((genTime.tm_month == 0) || (genTime.tm_month > 12))
+ goto loser;
+
+ /* NSPR month base is 0 */
+ --genTime.tm_month;
+
+ CAPTURE(genTime.tm_mday, string, loser);
+ if ((genTime.tm_mday == 0) || (genTime.tm_mday > 31))
+ goto loser;
+
+ CAPTURE(genTime.tm_hour, string, loser);
+ if (genTime.tm_hour > 23)
+ goto loser;
+
+ CAPTURE(genTime.tm_min, string, loser);
+ if (genTime.tm_min > 59)
+ goto loser;
+
+ if (ISDIGIT(string[0])) {
+ CAPTURE(genTime.tm_sec, string, loser);
+ if (genTime.tm_sec > 59)
+ goto loser;
+ }
+ signum = *string++;
+ if (signum == '+' || signum == '-') {
+ CAPTURE(hourOff, string, loser);
+ if (hourOff > 23)
+ goto loser;
+ CAPTURE(minOff, string, loser);
+ if (minOff > 59)
+ goto loser;
+ if (signum == '-') {
+ hourOff = -hourOff;
+ minOff = -minOff;
+ }
+ } else if (signum != 'Z') {
+ goto loser;
+ }
+
+ if (endptr)
+ *endptr = string;
+
+ /* Convert the GMT offset to seconds and save it in genTime
+ * for the implode time call.
+ */
+ genTime.tm_params.tp_gmt_offset = (PRInt32)((hourOff * 60L + minOff) * 60L);
+ *dst = PR_ImplodeTime(&genTime);
+ return SECSuccess;
+
+loser:
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+}
diff --git a/lib/util/errstrs.c b/lib/util/errstrs.c
new file mode 100644
index 000000000..a47554d62
--- /dev/null
+++ b/lib/util/errstrs.c
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "prerror.h"
+#include "secerr.h"
+#include "secport.h"
+#include "prinit.h"
+#include "prprf.h"
+#include "prtypes.h"
+#include "prlog.h"
+#include "plstr.h"
+#include "nssutil.h"
+#include <string.h>
+
+#define ER3(name, value, str) {#name, str},
+
+static const struct PRErrorMessage sectext[] = {
+#include "SECerrs.h"
+ {0,0}
+};
+
+static const struct PRErrorTable sec_et = {
+ sectext, "secerrstrings", SEC_ERROR_BASE,
+ (sizeof sectext)/(sizeof sectext[0])
+};
+
+static PRStatus
+nss_InitializePRErrorTableOnce(void) {
+ return PR_ErrorInstallTable(&sec_et);
+}
+
+static PRCallOnceType once;
+
+SECStatus
+NSS_InitializePRErrorTable(void)
+{
+ return (PR_SUCCESS == PR_CallOnce(&once, nss_InitializePRErrorTableOnce))
+ ? SECSuccess : SECFailure;
+}
+
diff --git a/lib/util/hasht.h b/lib/util/hasht.h
new file mode 100644
index 000000000..6fd12f13a
--- /dev/null
+++ b/lib/util/hasht.h
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* $Id$ */
+
+#ifndef _HASHT_H_
+#define _HASHT_H_
+
+/* Opaque objects */
+typedef struct SECHashObjectStr SECHashObject;
+typedef struct HASHContextStr HASHContext;
+
+/*
+ * The hash functions the security library supports
+ * NOTE the order must match the definition of SECHashObjects[]!
+ */
+typedef enum {
+ HASH_AlgNULL = 0,
+ HASH_AlgMD2 = 1,
+ HASH_AlgMD5 = 2,
+ HASH_AlgSHA1 = 3,
+ HASH_AlgSHA256 = 4,
+ HASH_AlgSHA384 = 5,
+ HASH_AlgSHA512 = 6,
+ HASH_AlgSHA224 = 7,
+ HASH_AlgTOTAL
+} HASH_HashType;
+
+/*
+ * Number of bytes each hash algorithm produces
+ */
+#define MD2_LENGTH 16
+#define MD5_LENGTH 16
+#define SHA1_LENGTH 20
+#define SHA224_LENGTH 28
+#define SHA256_LENGTH 32
+#define SHA384_LENGTH 48
+#define SHA512_LENGTH 64
+#define HASH_LENGTH_MAX SHA512_LENGTH
+
+/*
+ * Structure to hold hash computation info and routines
+ */
+struct SECHashObjectStr {
+ unsigned int length; /* hash output length (in bytes) */
+ void * (*create)(void);
+ void * (*clone)(void *);
+ void (*destroy)(void *, PRBool);
+ void (*begin)(void *);
+ void (*update)(void *, const unsigned char *, unsigned int);
+ void (*end)(void *, unsigned char *, unsigned int *, unsigned int);
+ unsigned int blocklength; /* hash input block size (in bytes) */
+ HASH_HashType type;
+ void (*end_raw)(void *, unsigned char *, unsigned int *, unsigned int);
+};
+
+struct HASHContextStr {
+ const struct SECHashObjectStr *hashobj;
+ void *hash_context;
+};
+
+#endif /* _HASHT_H_ */
diff --git a/lib/util/manifest.mn b/lib/util/manifest.mn
new file mode 100644
index 000000000..60ccaff08
--- /dev/null
+++ b/lib/util/manifest.mn
@@ -0,0 +1,86 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../../..
+
+EXPORTS = \
+ base64.h \
+ ciferfam.h \
+ hasht.h \
+ nssb64.h \
+ nssb64t.h \
+ nsslocks.h \
+ nssilock.h \
+ nssilckt.h \
+ nssrwlk.h \
+ nssrwlkt.h \
+ nssutil.h \
+ pkcs11.h \
+ pkcs11f.h \
+ pkcs11p.h \
+ pkcs11t.h \
+ pkcs11n.h \
+ pkcs11u.h \
+ portreg.h \
+ secasn1.h \
+ secasn1t.h \
+ seccomon.h \
+ secder.h \
+ secdert.h \
+ secdig.h \
+ secdigt.h \
+ secitem.h \
+ secoid.h \
+ secoidt.h \
+ secport.h \
+ secerr.h \
+ utilmodt.h \
+ utilrename.h \
+ utilpars.h \
+ utilparst.h \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ templates.c \
+ $(NULL)
+
+CSRCS = \
+ quickder.c \
+ secdig.c \
+ derdec.c \
+ derenc.c \
+ dersubr.c \
+ dertime.c \
+ errstrs.c \
+ nssb64d.c \
+ nssb64e.c \
+ nssrwlk.c \
+ nssilock.c \
+ oidstring.c \
+ portreg.c \
+ secalgid.c \
+ secasn1d.c \
+ secasn1e.c \
+ secasn1u.c \
+ secitem.c \
+ secload.c \
+ secoid.c \
+ sectime.c \
+ secport.c \
+ templates.c \
+ utf8.c \
+ utilmod.c \
+ utilpars.c \
+ $(NULL)
+
+MODULE = nss
+
+# don't duplicate module name in REQUIRES
+MAPFILE = $(OBJDIR)/nssutil.def
+
+LIBRARY_NAME = nssutil
+LIBRARY_VERSION = 3
+
+# This part of the code, including all sub-dirs, can be optimized for size
+export ALLOW_OPT_CODE_SIZE = 1
diff --git a/lib/util/nssb64.h b/lib/util/nssb64.h
new file mode 100644
index 000000000..76e7d9e76
--- /dev/null
+++ b/lib/util/nssb64.h
@@ -0,0 +1,96 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Public prototypes for base64 encoding/decoding.
+ *
+ * $Id$
+ */
+#ifndef _NSSB64_H_
+#define _NSSB64_H_
+
+#include "utilrename.h"
+#include "seccomon.h"
+#include "nssb64t.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+ * Functions to start a base64 decoding/encoding context.
+ */
+
+extern NSSBase64Decoder *
+NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
+ PRInt32),
+ void *output_arg);
+
+extern NSSBase64Encoder *
+NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+ void *output_arg);
+
+/*
+ * Push data through the decoder/encoder, causing the output_fn (provided
+ * to Create) to be called with the decoded/encoded data.
+ */
+
+extern SECStatus
+NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
+ PRUint32 size);
+
+extern SECStatus
+NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
+ PRUint32 size);
+
+/*
+ * When you're done processing, call this to close the context.
+ * If "abort_p" is false, then calling this may cause the output_fn
+ * to be called one last time (as the last buffered data is flushed out).
+ */
+
+extern SECStatus
+NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p);
+
+extern SECStatus
+NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p);
+
+/*
+ * Perform base64 decoding from an ascii string "inStr" to an Item.
+ * The length of the input must be provided as "inLen". The Item
+ * may be provided (as "outItemOpt"); you can also pass in a NULL
+ * and the Item will be allocated for you.
+ *
+ * In any case, the data within the Item will be allocated for you.
+ * All allocation will happen out of the passed-in "arenaOpt", if non-NULL.
+ * If "arenaOpt" is NULL, standard allocation (heap) will be used and
+ * you will want to free the result via SECITEM_FreeItem.
+ *
+ * Return value is NULL on error, the Item (allocated or provided) otherwise.
+ */
+extern SECItem *
+NSSBase64_DecodeBuffer (PLArenaPool *arenaOpt, SECItem *outItemOpt,
+ const char *inStr, unsigned int inLen);
+
+/*
+ * Perform base64 encoding of binary data "inItem" to an ascii string.
+ * The output buffer may be provided (as "outStrOpt"); you can also pass
+ * in a NULL and the buffer will be allocated for you. The result will
+ * be null-terminated, and if the buffer is provided, "maxOutLen" must
+ * specify the maximum length of the buffer and will be checked to
+ * supply sufficient space space for the encoded result. (If "outStrOpt"
+ * is NULL, "maxOutLen" is ignored.)
+ *
+ * If "outStrOpt" is NULL, allocation will happen out of the passed-in
+ * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap)
+ * will be used.
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+extern char *
+NSSBase64_EncodeItem (PLArenaPool *arenaOpt, char *outStrOpt,
+ unsigned int maxOutLen, SECItem *inItem);
+
+SEC_END_PROTOS
+
+#endif /* _NSSB64_H_ */
diff --git a/lib/util/nssb64d.c b/lib/util/nssb64d.c
new file mode 100644
index 000000000..0cf587cc9
--- /dev/null
+++ b/lib/util/nssb64d.c
@@ -0,0 +1,838 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Base64 decoding (ascii to binary).
+ *
+ * $Id$
+ */
+
+#include "nssb64.h"
+#include "nspr.h"
+#include "secitem.h"
+#include "secerr.h"
+
+/*
+ * XXX We want this basic support to go into NSPR (the PL part).
+ * Until that can happen, the PL interface is going to be kept entirely
+ * internal here -- all static functions and opaque data structures.
+ * When someone can get it moved over into NSPR, that should be done:
+ * - giving everything names that are accepted by the NSPR module owners
+ * (though I tried to choose ones that would work without modification)
+ * - exporting the functions (remove static declarations and add
+ * to nssutil.def as necessary)
+ * - put prototypes into appropriate header file (probably replacing
+ * the entire current lib/libc/include/plbase64.h in NSPR)
+ * along with a typedef for the context structure (which should be
+ * kept opaque -- definition in the source file only, but typedef
+ * ala "typedef struct PLBase64FooStr PLBase64Foo;" in header file)
+ * - modify anything else as necessary to conform to NSPR required style
+ * (I looked but found no formatting guide to follow)
+ *
+ * You will want to move over everything from here down to the comment
+ * which says "XXX End of base64 decoding code to be moved into NSPR",
+ * into a new file in NSPR.
+ */
+
+/*
+ **************************************************************
+ * XXX Beginning of base64 decoding code to be moved into NSPR.
+ */
+
+/*
+ * This typedef would belong in the NSPR header file (i.e. plbase64.h).
+ */
+typedef struct PLBase64DecoderStr PLBase64Decoder;
+
+/*
+ * The following implementation of base64 decoding was based on code
+ * found in libmime (specifically, in mimeenc.c). It has been adapted to
+ * use PR types and naming as well as to provide other necessary semantics
+ * (like buffer-in/buffer-out in addition to "streaming" without undue
+ * performance hit of extra copying if you made the buffer versions
+ * use the output_fn). It also incorporates some aspects of the current
+ * NSPR base64 decoding code. As such, you may find similarities to
+ * both of those implementations. I tried to use names that reflected
+ * the original code when possible. For this reason you may find some
+ * inconsistencies -- libmime used lots of "in" and "out" whereas the
+ * NSPR version uses "src" and "dest"; sometimes I changed one to the other
+ * and sometimes I left them when I thought the subroutines were at least
+ * self-consistent.
+ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Opaque object used by the decoder to store state.
+ */
+struct PLBase64DecoderStr {
+ /* Current token (or portion, if token_size < 4) being decoded. */
+ unsigned char token[4];
+ int token_size;
+
+ /*
+ * Where to write the decoded data (used when streaming, not when
+ * doing all in-memory (buffer) operations).
+ *
+ * Note that this definition is chosen to be compatible with PR_Write.
+ */
+ PRInt32 (*output_fn) (void *output_arg, const unsigned char *buf,
+ PRInt32 size);
+ void *output_arg;
+
+ /*
+ * Where the decoded output goes -- either temporarily (in the streaming
+ * case, staged here before it goes to the output function) or what will
+ * be the entire buffered result for users of the buffer version.
+ */
+ unsigned char *output_buffer;
+ PRUint32 output_buflen; /* the total length of allocated buffer */
+ PRUint32 output_length; /* the length that is currently populated */
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Table to convert an ascii "code" to its corresponding binary value.
+ * For ease of use, the binary values in the table are the actual values
+ * PLUS ONE. This is so that the special value of zero can denote an
+ * invalid mapping; that was much easier than trying to fill in the other
+ * values with some value other than zero, and to check for it.
+ * Just remember to SUBTRACT ONE when using the value retrieved.
+ */
+static unsigned char base64_codetovaluep1[256] = {
+/* 0: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 8: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 16: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 24: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 32: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 40: */ 0, 0, 0, 63, 0, 0, 0, 64,
+/* 48: */ 53, 54, 55, 56, 57, 58, 59, 60,
+/* 56: */ 61, 62, 0, 0, 0, 0, 0, 0,
+/* 64: */ 0, 1, 2, 3, 4, 5, 6, 7,
+/* 72: */ 8, 9, 10, 11, 12, 13, 14, 15,
+/* 80: */ 16, 17, 18, 19, 20, 21, 22, 23,
+/* 88: */ 24, 25, 26, 0, 0, 0, 0, 0,
+/* 96: */ 0, 27, 28, 29, 30, 31, 32, 33,
+/* 104: */ 34, 35, 36, 37, 38, 39, 40, 41,
+/* 112: */ 42, 43, 44, 45, 46, 47, 48, 49,
+/* 120: */ 50, 51, 52, 0, 0, 0, 0, 0,
+/* 128: */ 0, 0, 0, 0, 0, 0, 0, 0
+/* and rest are all zero as well */
+};
+
+#define B64_PAD '='
+
+
+/*
+ * Reads 4; writes 3 (known, or expected, to have no trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_4to3 (const unsigned char *in, unsigned char *out)
+{
+ int j;
+ PRUint32 num = 0;
+ unsigned char bits;
+
+ for (j = 0; j < 4; j++) {
+ bits = base64_codetovaluep1[in[j]];
+ if (bits == 0)
+ return -1;
+ num = (num << 6) | (bits - 1);
+ }
+
+ out[0] = (unsigned char) (num >> 16);
+ out[1] = (unsigned char) ((num >> 8) & 0xFF);
+ out[2] = (unsigned char) (num & 0xFF);
+
+ return 3;
+}
+
+/*
+ * Reads 3; writes 2 (caller already confirmed EOF or trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_3to2 (const unsigned char *in, unsigned char *out)
+{
+ PRUint32 num = 0;
+ unsigned char bits1, bits2, bits3;
+
+ bits1 = base64_codetovaluep1[in[0]];
+ bits2 = base64_codetovaluep1[in[1]];
+ bits3 = base64_codetovaluep1[in[2]];
+
+ if ((bits1 == 0) || (bits2 == 0) || (bits3 == 0))
+ return -1;
+
+ num = ((PRUint32)(bits1 - 1)) << 10;
+ num |= ((PRUint32)(bits2 - 1)) << 4;
+ num |= ((PRUint32)(bits3 - 1)) >> 2;
+
+ out[0] = (unsigned char) (num >> 8);
+ out[1] = (unsigned char) (num & 0xFF);
+
+ return 2;
+}
+
+/*
+ * Reads 2; writes 1 (caller already confirmed EOF or trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_2to1 (const unsigned char *in, unsigned char *out)
+{
+ PRUint32 num = 0;
+ unsigned char bits1, bits2;
+
+ bits1 = base64_codetovaluep1[in[0]];
+ bits2 = base64_codetovaluep1[in[1]];
+
+ if ((bits1 == 0) || (bits2 == 0))
+ return -1;
+
+ num = ((PRUint32)(bits1 - 1)) << 2;
+ num |= ((PRUint32)(bits2 - 1)) >> 4;
+
+ out[0] = (unsigned char) num;
+
+ return 1;
+}
+
+/*
+ * Reads 4; writes 0-3. Returns bytes written or -1 on error.
+ * (Writes less than 3 only at (presumed) EOF.)
+ */
+static int
+pl_base64_decode_token (const unsigned char *in, unsigned char *out)
+{
+ if (in[3] != B64_PAD)
+ return pl_base64_decode_4to3 (in, out);
+
+ if (in[2] == B64_PAD)
+ return pl_base64_decode_2to1 (in, out);
+
+ return pl_base64_decode_3to2 (in, out);
+}
+
+static PRStatus
+pl_base64_decode_buffer (PLBase64Decoder *data, const unsigned char *in,
+ PRUint32 length)
+{
+ unsigned char *out = data->output_buffer;
+ unsigned char *token = data->token;
+ int i, n = 0;
+
+ i = data->token_size;
+ data->token_size = 0;
+
+ while (length > 0) {
+ while (i < 4 && length > 0) {
+ /*
+ * XXX Note that the following simply ignores any unexpected
+ * characters. This is exactly what the original code in
+ * libmime did, and I am leaving it. We certainly want to skip
+ * over whitespace (we must); this does much more than that.
+ * I am not confident changing it, and I don't want to slow
+ * the processing down doing more complicated checking, but
+ * someone else might have different ideas in the future.
+ */
+ if (base64_codetovaluep1[*in] > 0 || *in == B64_PAD)
+ token[i++] = *in;
+ in++;
+ length--;
+ }
+
+ if (i < 4) {
+ /* Didn't get enough for a complete token. */
+ data->token_size = i;
+ break;
+ }
+ i = 0;
+
+ PR_ASSERT((out - data->output_buffer + 3) <= data->output_buflen);
+
+ /*
+ * Assume we are not at the end; the following function only works
+ * for an internal token (no trailing padding characters) but is
+ * faster that way. If it hits an invalid character (padding) it
+ * will return an error; we break out of the loop and try again
+ * calling the routine that will handle a final token.
+ * Note that we intentionally do it this way rather than explicitly
+ * add a check for padding here (because that would just slow down
+ * the normal case) nor do we rely on checking whether we have more
+ * input to process (because that would also slow it down but also
+ * because we want to allow trailing garbage, especially white space
+ * and cannot tell that without read-ahead, also a slow proposition).
+ * Whew. Understand?
+ */
+ n = pl_base64_decode_4to3 (token, out);
+ if (n < 0)
+ break;
+
+ /* Advance "out" by the number of bytes just written to it. */
+ out += n;
+ n = 0;
+ }
+
+ /*
+ * See big comment above, before call to pl_base64_decode_4to3.
+ * Here we check if we error'd out of loop, and allow for the case
+ * that we are processing the last interesting token. If the routine
+ * which should handle padding characters also fails, then we just
+ * have bad input and give up.
+ */
+ if (n < 0) {
+ n = pl_base64_decode_token (token, out);
+ if (n < 0)
+ return PR_FAILURE;
+
+ out += n;
+ }
+
+ /*
+ * As explained above, we can get here with more input remaining, but
+ * it should be all characters we do not care about (i.e. would be
+ * ignored when transferring from "in" to "token" in loop above,
+ * except here we choose to ignore extraneous pad characters, too).
+ * Swallow it, performing that check. If we find more characters that
+ * we would expect to decode, something is wrong.
+ */
+ while (length > 0) {
+ if (base64_codetovaluep1[*in] > 0)
+ return PR_FAILURE;
+ in++;
+ length--;
+ }
+
+ /* Record the length of decoded data we have left in output_buffer. */
+ data->output_length = (PRUint32) (out - data->output_buffer);
+ return PR_SUCCESS;
+}
+
+/*
+ * Flush any remaining buffered characters. Given well-formed input,
+ * this will have nothing to do. If the input was missing the padding
+ * characters at the end, though, there could be 1-3 characters left
+ * behind -- we will tolerate that by adding the padding for them.
+ */
+static PRStatus
+pl_base64_decode_flush (PLBase64Decoder *data)
+{
+ int count;
+
+ /*
+ * If no remaining characters, or all are padding (also not well-formed
+ * input, but again, be tolerant), then nothing more to do. (And, that
+ * is considered successful.)
+ */
+ if (data->token_size == 0 || data->token[0] == B64_PAD)
+ return PR_SUCCESS;
+
+ /*
+ * Assume we have all the interesting input except for some expected
+ * padding characters. Add them and decode the resulting token.
+ */
+ while (data->token_size < 4)
+ data->token[data->token_size++] = B64_PAD;
+
+ data->token_size = 0; /* so a subsequent flush call is a no-op */
+
+ count = pl_base64_decode_token (data->token,
+ data->output_buffer + data->output_length);
+ if (count < 0)
+ return PR_FAILURE;
+
+ /*
+ * If there is an output function, call it with this last bit of data.
+ * Otherwise we are doing all buffered output, and the decoded bytes
+ * are now there, we just need to reflect that in the length.
+ */
+ if (data->output_fn != NULL) {
+ PRInt32 output_result;
+
+ PR_ASSERT(data->output_length == 0);
+ output_result = data->output_fn (data->output_arg,
+ data->output_buffer,
+ (PRInt32) count);
+ if (output_result < 0)
+ return PR_FAILURE;
+ } else {
+ data->output_length += count;
+ }
+
+ return PR_SUCCESS;
+}
+
+
+/*
+ * The maximum space needed to hold the output of the decoder given
+ * input data of length "size".
+ */
+static PRUint32
+PL_Base64MaxDecodedLength (PRUint32 size)
+{
+ return ((size * 3) / 4);
+}
+
+
+/*
+ * A distinct internal creation function for the buffer version to use.
+ * (It does not want to specify an output_fn, and we want the normal
+ * Create function to require that.) If more common initialization
+ * of the decoding context needs to be done, it should be done *here*.
+ */
+static PLBase64Decoder *
+pl_base64_create_decoder (void)
+{
+ return PR_NEWZAP(PLBase64Decoder);
+}
+
+/*
+ * Function to start a base64 decoding context.
+ * An "output_fn" is required; the "output_arg" parameter to that is optional.
+ */
+static PLBase64Decoder *
+PL_CreateBase64Decoder (PRInt32 (*output_fn) (void *, const unsigned char *,
+ PRInt32),
+ void *output_arg)
+{
+ PLBase64Decoder *data;
+
+ if (output_fn == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+ }
+
+ data = pl_base64_create_decoder ();
+ if (data != NULL) {
+ data->output_fn = output_fn;
+ data->output_arg = output_arg;
+ }
+ return data;
+}
+
+
+/*
+ * Push data through the decoder, causing the output_fn (provided to Create)
+ * to be called with the decoded data.
+ */
+static PRStatus
+PL_UpdateBase64Decoder (PLBase64Decoder *data, const char *buffer,
+ PRUint32 size)
+{
+ PRUint32 need_length;
+ PRStatus status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL || buffer == NULL || size == 0) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ /*
+ * How much space could this update need for decoding?
+ */
+ need_length = PL_Base64MaxDecodedLength (size + data->token_size);
+
+ /*
+ * Make sure we have at least that much. If not, (re-)allocate.
+ */
+ if (need_length > data->output_buflen) {
+ unsigned char *output_buffer = data->output_buffer;
+
+ if (output_buffer != NULL)
+ output_buffer = (unsigned char *) PR_Realloc(output_buffer,
+ need_length);
+ else
+ output_buffer = (unsigned char *) PR_Malloc(need_length);
+
+ if (output_buffer == NULL)
+ return PR_FAILURE;
+
+ data->output_buffer = output_buffer;
+ data->output_buflen = need_length;
+ }
+
+ /* There should not have been any leftover output data in the buffer. */
+ PR_ASSERT(data->output_length == 0);
+ data->output_length = 0;
+
+ status = pl_base64_decode_buffer (data, (const unsigned char *) buffer,
+ size);
+
+ /* Now that we have some decoded data, write it. */
+ if (status == PR_SUCCESS && data->output_length > 0) {
+ PRInt32 output_result;
+
+ PR_ASSERT(data->output_fn != NULL);
+ output_result = data->output_fn (data->output_arg,
+ data->output_buffer,
+ (PRInt32) data->output_length);
+ if (output_result < 0)
+ status = PR_FAILURE;
+ }
+
+ data->output_length = 0;
+ return status;
+}
+
+
+/*
+ * When you're done decoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+static PRStatus
+PL_DestroyBase64Decoder (PLBase64Decoder *data, PRBool abort_p)
+{
+ PRStatus status = PR_SUCCESS;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ /* Flush out the last few buffered characters. */
+ if (!abort_p)
+ status = pl_base64_decode_flush (data);
+
+ if (data->output_buffer != NULL)
+ PR_Free(data->output_buffer);
+ PR_Free(data);
+
+ return status;
+}
+
+
+/*
+ * Perform base64 decoding from an input buffer to an output buffer.
+ * The output buffer can be provided (as "dest"); you can also pass in
+ * a NULL and this function will allocate a buffer large enough for you,
+ * and return it. If you do provide the output buffer, you must also
+ * provide the maximum length of that buffer (as "maxdestlen").
+ * The actual decoded length of output will be returned to you in
+ * "output_destlen".
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+static unsigned char *
+PL_Base64DecodeBuffer (const char *src, PRUint32 srclen, unsigned char *dest,
+ PRUint32 maxdestlen, PRUint32 *output_destlen)
+{
+ PRUint32 need_length;
+ unsigned char *output_buffer = NULL;
+ PLBase64Decoder *data = NULL;
+ PRStatus status;
+
+ PR_ASSERT(srclen > 0);
+ if (srclen == 0) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+ }
+
+ /*
+ * How much space could we possibly need for decoding this input?
+ */
+ need_length = PL_Base64MaxDecodedLength (srclen);
+
+ /*
+ * Make sure we have at least that much, if output buffer provided.
+ * If no output buffer provided, then we allocate that much.
+ */
+ if (dest != NULL) {
+ PR_ASSERT(maxdestlen >= need_length);
+ if (maxdestlen < need_length) {
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+ goto loser;
+ }
+ output_buffer = dest;
+ } else {
+ output_buffer = (unsigned char *) PR_Malloc(need_length);
+ if (output_buffer == NULL)
+ goto loser;
+ maxdestlen = need_length;
+ }
+
+ data = pl_base64_create_decoder();
+ if (data == NULL)
+ goto loser;
+
+ data->output_buflen = maxdestlen;
+ data->output_buffer = output_buffer;
+
+ status = pl_base64_decode_buffer (data, (const unsigned char *) src,
+ srclen);
+
+ /*
+ * We do not wait for Destroy to flush, because Destroy will also
+ * get rid of our decoder context, which we need to look at first!
+ */
+ if (status == PR_SUCCESS)
+ status = pl_base64_decode_flush (data);
+
+ /* Must clear this or Destroy will free it. */
+ data->output_buffer = NULL;
+
+ if (status == PR_SUCCESS) {
+ *output_destlen = data->output_length;
+ status = PL_DestroyBase64Decoder (data, PR_FALSE);
+ data = NULL;
+ if (status == PR_FAILURE)
+ goto loser;
+ return output_buffer;
+ }
+
+loser:
+ if (dest == NULL && output_buffer != NULL)
+ PR_Free(output_buffer);
+ if (data != NULL)
+ (void) PL_DestroyBase64Decoder (data, PR_TRUE);
+ return NULL;
+}
+
+
+/*
+ * XXX End of base64 decoding code to be moved into NSPR.
+ ********************************************************
+ */
+
+/*
+ * This is the beginning of the NSS cover functions. These will
+ * provide the interface we want to expose as NSS-ish. For example,
+ * they will operate on our Items, do any special handling or checking
+ * we want to do, etc.
+ */
+
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A boring cover structure for now. Perhaps someday it will include
+ * some more interesting fields.
+ */
+struct NSSBase64DecoderStr {
+ PLBase64Decoder *pl_data;
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Function to start a base64 decoding context.
+ */
+NSSBase64Decoder *
+NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
+ PRInt32),
+ void *output_arg)
+{
+ PLBase64Decoder *pl_data;
+ NSSBase64Decoder *nss_data;
+
+ nss_data = PORT_ZNew(NSSBase64Decoder);
+ if (nss_data == NULL)
+ return NULL;
+
+ pl_data = PL_CreateBase64Decoder (output_fn, output_arg);
+ if (pl_data == NULL) {
+ PORT_Free(nss_data);
+ return NULL;
+ }
+
+ nss_data->pl_data = pl_data;
+ return nss_data;
+}
+
+
+/*
+ * Push data through the decoder, causing the output_fn (provided to Create)
+ * to be called with the decoded data.
+ */
+SECStatus
+NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
+ PRUint32 size)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_UpdateBase64Decoder (data->pl_data, buffer, size);
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * When you're done decoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+SECStatus
+NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_DestroyBase64Decoder (data->pl_data, abort_p);
+
+ PORT_Free(data);
+
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * Perform base64 decoding from an ascii string "inStr" to an Item.
+ * The length of the input must be provided as "inLen". The Item
+ * may be provided (as "outItemOpt"); you can also pass in a NULL
+ * and the Item will be allocated for you.
+ *
+ * In any case, the data within the Item will be allocated for you.
+ * All allocation will happen out of the passed-in "arenaOpt", if non-NULL.
+ * If "arenaOpt" is NULL, standard allocation (heap) will be used and
+ * you will want to free the result via SECITEM_FreeItem.
+ *
+ * Return value is NULL on error, the Item (allocated or provided) otherwise.
+ */
+SECItem *
+NSSBase64_DecodeBuffer (PRArenaPool *arenaOpt, SECItem *outItemOpt,
+ const char *inStr, unsigned int inLen)
+{
+ SECItem *out_item = NULL;
+ PRUint32 max_out_len = 0;
+ PRUint32 out_len;
+ void *mark = NULL;
+ unsigned char *dummy;
+
+ if ((outItemOpt != NULL && outItemOpt->data != NULL) || inLen == 0) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ if (arenaOpt != NULL)
+ mark = PORT_ArenaMark (arenaOpt);
+
+ max_out_len = PL_Base64MaxDecodedLength (inLen);
+ out_item = SECITEM_AllocItem (arenaOpt, outItemOpt, max_out_len);
+ if (out_item == NULL) {
+ if (arenaOpt != NULL)
+ PORT_ArenaRelease (arenaOpt, mark);
+ return NULL;
+ }
+
+ dummy = PL_Base64DecodeBuffer (inStr, inLen, out_item->data,
+ max_out_len, &out_len);
+ if (dummy == NULL) {
+ if (arenaOpt != NULL) {
+ PORT_ArenaRelease (arenaOpt, mark);
+ if (outItemOpt != NULL) {
+ outItemOpt->data = NULL;
+ outItemOpt->len = 0;
+ }
+ } else {
+ SECITEM_FreeItem (out_item,
+ (outItemOpt == NULL) ? PR_TRUE : PR_FALSE);
+ }
+ return NULL;
+ }
+
+ if (arenaOpt != NULL)
+ PORT_ArenaUnmark (arenaOpt, mark);
+ out_item->len = out_len;
+ return out_item;
+}
+
+
+/*
+ * XXX Everything below is deprecated. If you add new stuff, put it
+ * *above*, not below.
+ */
+
+/*
+ * XXX The following "ATOB" functions are provided for backward compatibility
+ * with current code. They should be considered strongly deprecated.
+ * When we can convert all our code over to using the new NSSBase64Decoder_
+ * functions defined above, we should get rid of these altogether. (Remove
+ * protoypes from base64.h as well -- actually, remove that file completely).
+ * If someone thinks either of these functions provides such a very useful
+ * interface (though, as shown, the same functionality can already be
+ * obtained by calling NSSBase64_DecodeBuffer directly), fine -- but then
+ * that API should be provided with a nice new NSSFoo name and using
+ * appropriate types, etc.
+ */
+
+#include "base64.h"
+
+/*
+** Return an PORT_Alloc'd string which is the base64 decoded version
+** of the input string; set *lenp to the length of the returned data.
+*/
+unsigned char *
+ATOB_AsciiToData(const char *string, unsigned int *lenp)
+{
+ SECItem binary_item, *dummy;
+
+ binary_item.data = NULL;
+ binary_item.len = 0;
+
+ dummy = NSSBase64_DecodeBuffer (NULL, &binary_item, string,
+ (PRUint32) PORT_Strlen(string));
+ if (dummy == NULL)
+ return NULL;
+
+ PORT_Assert(dummy == &binary_item);
+
+ *lenp = dummy->len;
+ return dummy->data;
+}
+
+/*
+** Convert from ascii to binary encoding of an item.
+*/
+SECStatus
+ATOB_ConvertAsciiToItem(SECItem *binary_item, const char *ascii)
+{
+ SECItem *dummy;
+
+ if (binary_item == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /*
+ * XXX Would prefer to assert here if data is non-null (actually,
+ * don't need to, just let NSSBase64_DecodeBuffer do it), so as to
+ * to catch unintended memory leaks, but callers are not clean in
+ * this respect so we need to explicitly clear here to avoid the
+ * assert in NSSBase64_DecodeBuffer.
+ */
+ binary_item->data = NULL;
+ binary_item->len = 0;
+
+ dummy = NSSBase64_DecodeBuffer (NULL, binary_item, ascii,
+ (PRUint32) PORT_Strlen(ascii));
+
+ if (dummy == NULL)
+ return SECFailure;
+
+ return SECSuccess;
+}
diff --git a/lib/util/nssb64e.c b/lib/util/nssb64e.c
new file mode 100644
index 000000000..4aff4ff59
--- /dev/null
+++ b/lib/util/nssb64e.c
@@ -0,0 +1,733 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Base64 encoding (binary to ascii).
+ *
+ * $Id$
+ */
+
+#include "nssb64.h"
+#include "nspr.h"
+#include "secitem.h"
+#include "secerr.h"
+
+/*
+ * XXX See the big comment at the top of nssb64d.c about moving the
+ * bulk of this code over into NSPR (the PL part). It all applies
+ * here but I didn't want to duplicate it, to avoid divergence problems.
+ */
+
+/*
+ **************************************************************
+ * XXX Beginning of base64 encoding code to be moved into NSPR.
+ */
+
+
+struct PLBase64EncodeStateStr {
+ unsigned chunks;
+ unsigned saved;
+ unsigned char buf[3];
+};
+
+/*
+ * This typedef would belong in the NSPR header file (i.e. plbase64.h).
+ */
+typedef struct PLBase64EncoderStr PLBase64Encoder;
+
+/*
+ * The following implementation of base64 encoding was based on code
+ * found in libmime (specifically, in mimeenc.c). It has been adapted to
+ * use PR types and naming as well as to provide other necessary semantics
+ * (like buffer-in/buffer-out in addition to "streaming" without undue
+ * performance hit of extra copying if you made the buffer versions
+ * use the output_fn). It also incorporates some aspects of the current
+ * NSPR base64 encoding code. As such, you may find similarities to
+ * both of those implementations. I tried to use names that reflected
+ * the original code when possible. For this reason you may find some
+ * inconsistencies -- libmime used lots of "in" and "out" whereas the
+ * NSPR version uses "src" and "dest"; sometimes I changed one to the other
+ * and sometimes I left them when I thought the subroutines were at least
+ * self-consistent.
+ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Opaque object used by the encoder to store state.
+ */
+struct PLBase64EncoderStr {
+ /*
+ * The one or two bytes pending. (We need 3 to create a "token",
+ * and hold the leftovers here. in_buffer_count is *only* ever
+ * 0, 1, or 2.
+ */
+ unsigned char in_buffer[2];
+ int in_buffer_count;
+
+ /*
+ * If the caller wants linebreaks added, line_length specifies
+ * where they come out. It must be a multiple of 4; if the caller
+ * provides one that isn't, we round it down to the nearest
+ * multiple of 4.
+ *
+ * The value of current_column counts how many characters have been
+ * added since the last linebreaks (or since the beginning, on the
+ * first line). It is also always a multiple of 4; it is unused when
+ * line_length is 0.
+ */
+ PRUint32 line_length;
+ PRUint32 current_column;
+
+ /*
+ * Where to write the encoded data (used when streaming, not when
+ * doing all in-memory (buffer) operations).
+ *
+ * Note that this definition is chosen to be compatible with PR_Write.
+ */
+ PRInt32 (*output_fn) (void *output_arg, const char *buf, PRInt32 size);
+ void *output_arg;
+
+ /*
+ * Where the encoded output goes -- either temporarily (in the streaming
+ * case, staged here before it goes to the output function) or what will
+ * be the entire buffered result for users of the buffer version.
+ */
+ char *output_buffer;
+ PRUint32 output_buflen; /* the total length of allocated buffer */
+ PRUint32 output_length; /* the length that is currently populated */
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Table to convert a binary value to its corresponding ascii "code".
+ */
+static unsigned char base64_valuetocode[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define B64_PAD '='
+#define B64_CR '\r'
+#define B64_LF '\n'
+
+static PRStatus
+pl_base64_encode_buffer (PLBase64Encoder *data, const unsigned char *in,
+ PRUint32 size)
+{
+ const unsigned char *end = in + size;
+ char *out = data->output_buffer + data->output_length;
+ unsigned int i = data->in_buffer_count;
+ PRUint32 n = 0;
+ int off;
+ PRUint32 output_threshold;
+
+ /* If this input buffer is too small, wait until next time. */
+ if (size < (3 - i)) {
+ data->in_buffer[i++] = in[0];
+ if (size > 1)
+ data->in_buffer[i++] = in[1];
+ PR_ASSERT(i < 3);
+ data->in_buffer_count = i;
+ return PR_SUCCESS;
+ }
+
+ /* If there are bytes that were put back last time, take them now. */
+ if (i > 0) {
+ n = data->in_buffer[0];
+ if (i > 1)
+ n = (n << 8) | data->in_buffer[1];
+ data->in_buffer_count = 0;
+ }
+
+ /* If our total is not a multiple of three, put one or two bytes back. */
+ off = (size + i) % 3;
+ if (off > 0) {
+ size -= off;
+ data->in_buffer[0] = in[size];
+ if (off > 1)
+ data->in_buffer[1] = in[size + 1];
+ data->in_buffer_count = off;
+ end -= off;
+ }
+
+ output_threshold = data->output_buflen - 3;
+
+ /*
+ * Populate the output buffer with base64 data, one line (or buffer)
+ * at a time.
+ */
+ while (in < end) {
+ int j, k;
+
+ while (i < 3) {
+ n = (n << 8) | *in++;
+ i++;
+ }
+ i = 0;
+
+ if (data->line_length > 0) {
+ if (data->current_column >= data->line_length) {
+ data->current_column = 0;
+ *out++ = B64_CR;
+ *out++ = B64_LF;
+ data->output_length += 2;
+ }
+ data->current_column += 4; /* the bytes we are about to add */
+ }
+
+ for (j = 18; j >= 0; j -= 6) {
+ k = (n >> j) & 0x3F;
+ *out++ = base64_valuetocode[k];
+ }
+ n = 0;
+ data->output_length += 4;
+
+ if (data->output_length >= output_threshold) {
+ PR_ASSERT(data->output_length <= data->output_buflen);
+ if (data->output_fn != NULL) {
+ PRInt32 output_result;
+
+ output_result = data->output_fn (data->output_arg,
+ data->output_buffer,
+ (PRInt32) data->output_length);
+ if (output_result < 0)
+ return PR_FAILURE;
+
+ out = data->output_buffer;
+ data->output_length = 0;
+ } else {
+ /*
+ * Check that we are about to exit the loop. (Since we
+ * are over the threshold, there isn't enough room in the
+ * output buffer for another trip around.)
+ */
+ PR_ASSERT(in == end);
+ if (in < end) {
+ PR_SetError (PR_BUFFER_OVERFLOW_ERROR, 0);
+ return PR_FAILURE;
+ }
+ }
+ }
+ }
+
+ return PR_SUCCESS;
+}
+
+static PRStatus
+pl_base64_encode_flush (PLBase64Encoder *data)
+{
+ int i = data->in_buffer_count;
+
+ if (i == 0 && data->output_length == 0)
+ return PR_SUCCESS;
+
+ if (i > 0) {
+ char *out = data->output_buffer + data->output_length;
+ PRUint32 n;
+ int j, k;
+
+ n = ((PRUint32) data->in_buffer[0]) << 16;
+ if (i > 1)
+ n |= ((PRUint32) data->in_buffer[1] << 8);
+
+ data->in_buffer_count = 0;
+
+ if (data->line_length > 0) {
+ if (data->current_column >= data->line_length) {
+ data->current_column = 0;
+ *out++ = B64_CR;
+ *out++ = B64_LF;
+ data->output_length += 2;
+ }
+ }
+
+ /*
+ * This will fill in more than we really have data for, but the
+ * valid parts will end up in the correct position and the extras
+ * will be over-written with pad characters below.
+ */
+ for (j = 18; j >= 0; j -= 6) {
+ k = (n >> j) & 0x3F;
+ *out++ = base64_valuetocode[k];
+ }
+
+ /* Pad with equal-signs. */
+ if (i == 1)
+ out[-2] = B64_PAD;
+ out[-1] = B64_PAD;
+
+ data->output_length += 4;
+ }
+
+ if (data->output_fn != NULL) {
+ PRInt32 output_result;
+
+ output_result = data->output_fn (data->output_arg, data->output_buffer,
+ (PRInt32) data->output_length);
+ data->output_length = 0;
+
+ if (output_result < 0)
+ return PR_FAILURE;
+ }
+
+ return PR_SUCCESS;
+}
+
+
+/*
+ * The maximum space needed to hold the output of the encoder given input
+ * data of length "size", and allowing for CRLF added at least every
+ * line_length bytes (we will add it at nearest lower multiple of 4).
+ * There is no trailing CRLF.
+ */
+static PRUint32
+PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length)
+{
+ PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder;
+
+ tokens = (size + 2) / 3;
+
+ if (line_length == 0)
+ return tokens * 4;
+
+ if (line_length < 4) /* too small! */
+ line_length = 4;
+
+ tokens_per_line = line_length / 4;
+ full_lines = tokens / tokens_per_line;
+ remainder = (tokens - (full_lines * tokens_per_line)) * 4;
+ line_break_chars = full_lines * 2;
+ if (remainder == 0)
+ line_break_chars -= 2;
+
+ return (full_lines * tokens_per_line * 4) + line_break_chars + remainder;
+}
+
+
+/*
+ * A distinct internal creation function for the buffer version to use.
+ * (It does not want to specify an output_fn, and we want the normal
+ * Create function to require that.) All common initialization of the
+ * encoding context should be done *here*.
+ *
+ * Save "line_length", rounded down to nearest multiple of 4 (if not
+ * already even multiple). Allocate output_buffer, if not provided --
+ * based on given size if specified, otherwise based on line_length.
+ */
+static PLBase64Encoder *
+pl_base64_create_encoder (PRUint32 line_length, char *output_buffer,
+ PRUint32 output_buflen)
+{
+ PLBase64Encoder *data;
+ PRUint32 line_tokens;
+
+ data = PR_NEWZAP(PLBase64Encoder);
+ if (data == NULL)
+ return NULL;
+
+ if (line_length > 0 && line_length < 4) /* too small! */
+ line_length = 4;
+
+ line_tokens = line_length / 4;
+ data->line_length = line_tokens * 4;
+
+ if (output_buffer == NULL) {
+ if (output_buflen == 0) {
+ if (data->line_length > 0) /* need to include room for CRLF */
+ output_buflen = data->line_length + 2;
+ else
+ output_buflen = 64; /* XXX what is a good size? */
+ }
+
+ output_buffer = (char *) PR_Malloc(output_buflen);
+ if (output_buffer == NULL) {
+ PR_Free(data);
+ return NULL;
+ }
+ }
+
+ data->output_buffer = output_buffer;
+ data->output_buflen = output_buflen;
+ return data;
+}
+
+/*
+ * Function to start a base64 encoding context.
+ * An "output_fn" is required; the "output_arg" parameter to that is optional.
+ * If linebreaks in the encoded output are desired, "line_length" specifies
+ * where to place them -- it will be rounded down to the nearest multiple of 4
+ * (if it is not already an even multiple of 4). If it is zero, no linebreaks
+ * will be added. (FYI, a linebreak is CRLF -- two characters.)
+ */
+static PLBase64Encoder *
+PL_CreateBase64Encoder (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+ void *output_arg, PRUint32 line_length)
+{
+ PLBase64Encoder *data;
+
+ if (output_fn == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+ }
+
+ data = pl_base64_create_encoder (line_length, NULL, 0);
+ if (data == NULL)
+ return NULL;
+
+ data->output_fn = output_fn;
+ data->output_arg = output_arg;
+
+ return data;
+}
+
+
+/*
+ * Push data through the encoder, causing the output_fn (provided to Create)
+ * to be called with the encoded data.
+ */
+static PRStatus
+PL_UpdateBase64Encoder (PLBase64Encoder *data, const unsigned char *buffer,
+ PRUint32 size)
+{
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL || buffer == NULL || size == 0) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ return pl_base64_encode_buffer (data, buffer, size);
+}
+
+
+/*
+ * When you're done encoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+static PRStatus
+PL_DestroyBase64Encoder (PLBase64Encoder *data, PRBool abort_p)
+{
+ PRStatus status = PR_SUCCESS;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ /* Flush out the last few buffered characters. */
+ if (!abort_p)
+ status = pl_base64_encode_flush (data);
+
+ if (data->output_buffer != NULL)
+ PR_Free(data->output_buffer);
+ PR_Free(data);
+
+ return status;
+}
+
+
+/*
+ * Perform base64 encoding from an input buffer to an output buffer.
+ * The output buffer can be provided (as "dest"); you can also pass in
+ * a NULL and this function will allocate a buffer large enough for you,
+ * and return it. If you do provide the output buffer, you must also
+ * provide the maximum length of that buffer (as "maxdestlen").
+ * The actual encoded length of output will be returned to you in
+ * "output_destlen".
+ *
+ * If linebreaks in the encoded output are desired, "line_length" specifies
+ * where to place them -- it will be rounded down to the nearest multiple of 4
+ * (if it is not already an even multiple of 4). If it is zero, no linebreaks
+ * will be added. (FYI, a linebreak is CRLF -- two characters.)
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+static char *
+PL_Base64EncodeBuffer (const unsigned char *src, PRUint32 srclen,
+ PRUint32 line_length, char *dest, PRUint32 maxdestlen,
+ PRUint32 *output_destlen)
+{
+ PRUint32 need_length;
+ PLBase64Encoder *data = NULL;
+ PRStatus status;
+
+ PR_ASSERT(srclen > 0);
+ if (srclen == 0)
+ return dest;
+
+ /*
+ * How much space could we possibly need for encoding this input?
+ */
+ need_length = PL_Base64MaxEncodedLength (srclen, line_length);
+
+ /*
+ * Make sure we have at least that much, if output buffer provided.
+ */
+ if (dest != NULL) {
+ PR_ASSERT(maxdestlen >= need_length);
+ if (maxdestlen < need_length) {
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+ return NULL;
+ }
+ } else {
+ maxdestlen = need_length;
+ }
+
+ data = pl_base64_create_encoder(line_length, dest, maxdestlen);
+ if (data == NULL)
+ return NULL;
+
+ status = pl_base64_encode_buffer (data, src, srclen);
+
+ /*
+ * We do not wait for Destroy to flush, because Destroy will also
+ * get rid of our encoder context, which we need to look at first!
+ */
+ if (status == PR_SUCCESS)
+ status = pl_base64_encode_flush (data);
+
+ if (status != PR_SUCCESS) {
+ (void) PL_DestroyBase64Encoder (data, PR_TRUE);
+ return NULL;
+ }
+
+ dest = data->output_buffer;
+
+ /* Must clear this or Destroy will free it. */
+ data->output_buffer = NULL;
+
+ *output_destlen = data->output_length;
+ status = PL_DestroyBase64Encoder (data, PR_FALSE);
+ if (status == PR_FAILURE) {
+ PR_Free(dest);
+ return NULL;
+ }
+
+ return dest;
+}
+
+/*
+ * XXX End of base64 encoding code to be moved into NSPR.
+ ********************************************************
+ */
+
+/*
+ * This is the beginning of the NSS cover functions. These will
+ * provide the interface we want to expose as NSS-ish. For example,
+ * they will operate on our Items, do any special handling or checking
+ * we want to do, etc.
+ */
+
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A boring cover structure for now. Perhaps someday it will include
+ * some more interesting fields.
+ */
+struct NSSBase64EncoderStr {
+ PLBase64Encoder *pl_data;
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Function to start a base64 encoding context.
+ */
+NSSBase64Encoder *
+NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+ void *output_arg)
+{
+ PLBase64Encoder *pl_data;
+ NSSBase64Encoder *nss_data;
+
+ nss_data = PORT_ZNew(NSSBase64Encoder);
+ if (nss_data == NULL)
+ return NULL;
+
+ pl_data = PL_CreateBase64Encoder (output_fn, output_arg, 64);
+ if (pl_data == NULL) {
+ PORT_Free(nss_data);
+ return NULL;
+ }
+
+ nss_data->pl_data = pl_data;
+ return nss_data;
+}
+
+
+/*
+ * Push data through the encoder, causing the output_fn (provided to Create)
+ * to be called with the encoded data.
+ */
+SECStatus
+NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
+ PRUint32 size)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_UpdateBase64Encoder (data->pl_data, buffer, size);
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * When you're done encoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+SECStatus
+NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_DestroyBase64Encoder (data->pl_data, abort_p);
+
+ PORT_Free(data);
+
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * Perform base64 encoding of binary data "inItem" to an ascii string.
+ * The output buffer may be provided (as "outStrOpt"); you can also pass
+ * in a NULL and the buffer will be allocated for you. The result will
+ * be null-terminated, and if the buffer is provided, "maxOutLen" must
+ * specify the maximum length of the buffer and will be checked to
+ * supply sufficient space space for the encoded result. (If "outStrOpt"
+ * is NULL, "maxOutLen" is ignored.)
+ *
+ * If "outStrOpt" is NULL, allocation will happen out of the passed-in
+ * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap)
+ * will be used.
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+char *
+NSSBase64_EncodeItem (PRArenaPool *arenaOpt, char *outStrOpt,
+ unsigned int maxOutLen, SECItem *inItem)
+{
+ char *out_string = outStrOpt;
+ PRUint32 max_out_len;
+ PRUint32 out_len;
+ void *mark = NULL;
+ char *dummy;
+
+ PORT_Assert(inItem != NULL && inItem->data != NULL && inItem->len != 0);
+ if (inItem == NULL || inItem->data == NULL || inItem->len == 0) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ max_out_len = PL_Base64MaxEncodedLength (inItem->len, 64);
+
+ if (arenaOpt != NULL)
+ mark = PORT_ArenaMark (arenaOpt);
+
+ if (out_string == NULL) {
+ if (arenaOpt != NULL)
+ out_string = PORT_ArenaAlloc (arenaOpt, max_out_len + 1);
+ else
+ out_string = PORT_Alloc (max_out_len + 1);
+
+ if (out_string == NULL) {
+ if (arenaOpt != NULL)
+ PORT_ArenaRelease (arenaOpt, mark);
+ return NULL;
+ }
+ } else {
+ if ((max_out_len + 1) > maxOutLen) {
+ PORT_SetError (SEC_ERROR_OUTPUT_LEN);
+ return NULL;
+ }
+ max_out_len = maxOutLen;
+ }
+
+
+ dummy = PL_Base64EncodeBuffer (inItem->data, inItem->len, 64,
+ out_string, max_out_len, &out_len);
+ if (dummy == NULL) {
+ if (arenaOpt != NULL) {
+ PORT_ArenaRelease (arenaOpt, mark);
+ } else {
+ PORT_Free (out_string);
+ }
+ return NULL;
+ }
+
+ if (arenaOpt != NULL)
+ PORT_ArenaUnmark (arenaOpt, mark);
+
+ out_string[out_len] = '\0';
+ return out_string;
+}
+
+
+/*
+ * XXX Everything below is deprecated. If you add new stuff, put it
+ * *above*, not below.
+ */
+
+/*
+ * XXX The following "BTOA" functions are provided for backward compatibility
+ * with current code. They should be considered strongly deprecated.
+ * When we can convert all our code over to using the new NSSBase64Encoder_
+ * functions defined above, we should get rid of these altogether. (Remove
+ * protoypes from base64.h as well -- actually, remove that file completely).
+ * If someone thinks either of these functions provides such a very useful
+ * interface (though, as shown, the same functionality can already be
+ * obtained by calling NSSBase64_EncodeItem directly), fine -- but then
+ * that API should be provided with a nice new NSSFoo name and using
+ * appropriate types, etc.
+ */
+
+#include "base64.h"
+
+/*
+** Return an PORT_Alloc'd ascii string which is the base64 encoded
+** version of the input string.
+*/
+char *
+BTOA_DataToAscii(const unsigned char *data, unsigned int len)
+{
+ SECItem binary_item;
+
+ binary_item.data = (unsigned char *)data;
+ binary_item.len = len;
+
+ return NSSBase64_EncodeItem (NULL, NULL, 0, &binary_item);
+}
+
+/*
+** Convert from binary encoding of an item to ascii.
+*/
+char *
+BTOA_ConvertItemToAscii (SECItem *binary_item)
+{
+ return NSSBase64_EncodeItem (NULL, NULL, 0, binary_item);
+}
diff --git a/lib/util/nssb64t.h b/lib/util/nssb64t.h
new file mode 100644
index 000000000..6717858a4
--- /dev/null
+++ b/lib/util/nssb64t.h
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Public data structures for base64 encoding/decoding.
+ *
+ * $Id$
+ */
+#ifndef _NSSB64T_H_
+#define _NSSB64T_H_
+
+#include "utilrename.h"
+typedef struct NSSBase64DecoderStr NSSBase64Decoder;
+typedef struct NSSBase64EncoderStr NSSBase64Encoder;
+
+#endif /* _NSSB64T_H_ */
diff --git a/lib/util/nssilckt.h b/lib/util/nssilckt.h
new file mode 100644
index 000000000..7108e0c28
--- /dev/null
+++ b/lib/util/nssilckt.h
@@ -0,0 +1,191 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** nssilock.h - Instrumented locking functions for NSS
+**
+** Description:
+** nssilock provides instrumentation for locks and monitors in
+** the NSS libraries. The instrumentation, when enabled, causes
+** each call to the instrumented function to record data about
+** the call to an external file. The external file
+** subsequently used to extract performance data and other
+** statistical information about the operation of locks used in
+** the nss library.
+**
+** To enable compilation with instrumentation, build NSS with
+** the compile time switch NEED_NSS_ILOCK defined.
+**
+** say: "gmake OS_CFLAGS+=-DNEED_NSS_ILOCK" at make time.
+**
+** At runtime, to enable recording from nssilock, one or more
+** environment variables must be set. For each nssILockType to
+** be recorded, an environment variable of the form NSS_ILOCK_x
+** must be set to 1. For example:
+**
+** set NSS_ILOCK_Cert=1
+**
+** nssilock uses PRLOG is used to record to trace data. The
+** PRLogModule name associated with nssilock data is: "nssilock".
+** To enable recording of nssilock data you will need to set the
+** environment variable NSPR_LOG_MODULES to enable
+** recording for the nssilock log module. Similarly, you will
+** need to set the environment variable NSPR_LOG_FILE to specify
+** the filename to receive the recorded data. See prlog.h for usage.
+** Example:
+**
+** export NSPR_LOG_MODULES=nssilock:6
+** export NSPR_LOG_FILE=xxxLogfile
+**
+** Operation:
+** nssilock wraps calls to NSPR's PZLock and PZMonitor functions
+** with similarly named functions: PZ_NewLock(), etc. When NSS is
+** built with lock instrumentation enabled, the PZ* functions are
+** compiled into NSS; when lock instrumentation is disabled,
+** calls to PZ* functions are directly mapped to PR* functions
+** and the instrumentation arguments to the PZ* functions are
+** compiled away.
+**
+**
+** File Format:
+** The format of the external file is implementation
+** dependent. Where NSPR's PR_LOG() function is used, the file
+** contains data defined for PR_LOG() plus the data written by
+** the wrapped function. On some platforms and under some
+** circumstances, platform dependent logging or
+** instrumentation probes may be used. In any case, the
+** relevant data provided by the lock instrumentation is:
+**
+** lockType, func, address, duration, line, file [heldTime]
+**
+** where:
+**
+** lockType: a character representation of nssILockType for the
+** call. e.g. ... "cert"
+**
+** func: the function doing the tracing. e.g. "NewLock"
+**
+** address: address of the instrumented lock or monitor
+**
+** duration: is how long was spent in the instrumented function,
+** in PRIntervalTime "ticks".
+**
+** line: the line number within the calling function
+**
+** file: the file from which the call was made
+**
+** heldTime: how long the lock/monitor was held. field
+** present only for PZ_Unlock() and PZ_ExitMonitor().
+**
+** Design Notes:
+** The design for lock instrumentation was influenced by the
+** need to gather performance data on NSS 3.x. It is intended
+** that the effort to modify NSS to use lock instrumentation
+** be minimized. Existing calls to locking functions need only
+** have their names changed to the instrumentation function
+** names.
+**
+** Private NSS Interface:
+** nssilock.h defines a private interface for use by NSS.
+** nssilock.h is experimental in nature and is subject to
+** change or revocation without notice. ... Don't mess with
+** it.
+**
+*/
+
+/*
+ * $Id:
+ */
+
+#ifndef _NSSILCKT_H_
+#define _NSSILCKT_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "prmon.h"
+#include "prlock.h"
+#include "prcvar.h"
+
+typedef enum {
+ nssILockArena = 0,
+ nssILockSession = 1,
+ nssILockObject = 2,
+ nssILockRefLock = 3,
+ nssILockCert = 4,
+ nssILockCertDB = 5,
+ nssILockDBM = 6,
+ nssILockCache = 7,
+ nssILockSSL = 8,
+ nssILockList = 9,
+ nssILockSlot = 10,
+ nssILockFreelist = 11,
+ nssILockOID = 12,
+ nssILockAttribute = 13,
+ nssILockPK11cxt = 14, /* pk11context */
+ nssILockRWLock = 15,
+ nssILockOther = 16,
+ nssILockSelfServ = 17,
+ nssILockKeyDB = 18,
+ nssILockLast /* don't use this one! */
+} nssILockType;
+
+/*
+** conditionally compile in nssilock features
+*/
+#if defined(NEED_NSS_ILOCK)
+
+/*
+** Declare operation type enumerator
+** enumerations identify the function being performed
+*/
+typedef enum {
+ FlushTT = 0,
+ NewLock = 1,
+ Lock = 2,
+ Unlock = 3,
+ DestroyLock = 4,
+ NewCondVar = 5,
+ WaitCondVar = 6,
+ NotifyCondVar = 7,
+ NotifyAllCondVar = 8,
+ DestroyCondVar = 9,
+ NewMonitor = 10,
+ EnterMonitor = 11,
+ ExitMonitor = 12,
+ Notify = 13,
+ NotifyAll = 14,
+ Wait = 15,
+ DestroyMonitor = 16
+} nssILockOp;
+
+/*
+** Declare the trace record
+*/
+struct pzTrace_s {
+ PRUint32 threadID; /* PR_GetThreadID() */
+ nssILockOp op; /* operation being performed */
+ nssILockType ltype; /* lock type identifier */
+ PRIntervalTime callTime; /* time spent in function */
+ PRIntervalTime heldTime; /* lock held time, or -1 */
+ void *lock; /* address of lock structure */
+ PRIntn line; /* line number */
+ char file[24]; /* filename */
+};
+
+/*
+** declare opaque types. See: nssilock.c
+*/
+typedef struct pzlock_s PZLock;
+typedef struct pzcondvar_s PZCondVar;
+typedef struct pzmonitor_s PZMonitor;
+
+#else /* NEED_NSS_ILOCK */
+
+#define PZLock PRLock
+#define PZCondVar PRCondVar
+#define PZMonitor PRMonitor
+
+#endif /* NEED_NSS_ILOCK */
+
+#endif /* _NSSILCKT_H_ */
diff --git a/lib/util/nssilock.c b/lib/util/nssilock.c
new file mode 100644
index 000000000..2799635fa
--- /dev/null
+++ b/lib/util/nssilock.c
@@ -0,0 +1,498 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * nssilock.c - NSS lock instrumentation wrapper functions
+ *
+ * NOTE - These are not public interfaces
+ *
+ * Implementation Notes:
+ * I've tried to make the instrumentation relatively non-intrusive.
+ * To do this, I have used a single PR_LOG() call in each
+ * instrumented function. There's room for improvement.
+ *
+ *
+ */
+
+#include "prinit.h"
+#include "prerror.h"
+#include "prlock.h"
+#include "prmem.h"
+#include "prenv.h"
+#include "prcvar.h"
+#include "prio.h"
+
+#if defined(NEED_NSS_ILOCK)
+#include "prlog.h"
+#include "nssilock.h"
+
+/*
+** Declare the instrumented PZLock
+*/
+struct pzlock_s {
+ PRLock *lock; /* the PZLock to be instrumented */
+ PRIntervalTime time; /* timestamp when the lock was aquired */
+ nssILockType ltype;
+};
+
+/*
+** Declare the instrumented PZMonitor
+*/
+struct pzmonitor_s {
+ PRMonitor *mon; /* the PZMonitor to be instrumented */
+ PRIntervalTime time; /* timestamp when the monitor was aquired */
+ nssILockType ltype;
+};
+
+/*
+** Declare the instrumented PZCondVar
+*/
+struct pzcondvar_s {
+ PRCondVar *cvar; /* the PZCondVar to be instrumented */
+ nssILockType ltype;
+};
+
+
+/*
+** Define a CallOnce type to ensure serialized self-initialization
+*/
+static PRCallOnceType coNssILock; /* CallOnce type */
+static PRIntn nssILockInitialized; /* initialization done when 1 */
+static PRLogModuleInfo *nssILog; /* Log instrumentation to this handle */
+
+
+#define NUM_TT_ENTRIES 6000000
+static PRInt32 traceIndex = -1; /* index into trace table */
+static struct pzTrace_s *tt; /* pointer to trace table */
+static PRInt32 ttBufSize = (NUM_TT_ENTRIES * sizeof(struct pzTrace_s ));
+static PRCondVar *ttCVar;
+static PRLock *ttLock;
+static PRFileDesc *ttfd; /* trace table file */
+
+/*
+** Vtrace() -- Trace events, write events to external media
+**
+** Vtrace() records traced events in an in-memory trace table
+** when the trace table fills, Vtrace writes the entire table
+** to a file.
+**
+** data can be lost!
+**
+*/
+static void Vtrace(
+ nssILockOp op,
+ nssILockType ltype,
+ PRIntervalTime callTime,
+ PRIntervalTime heldTime,
+ void *lock,
+ PRIntn line,
+ char *file
+) {
+ PRInt32 idx;
+ struct pzTrace_s *tp;
+
+RetryTrace:
+ idx = PR_ATOMIC_INCREMENT( &traceIndex );
+ while( NUM_TT_ENTRIES <= idx || op == FlushTT ) {
+ if( NUM_TT_ENTRIES == idx || op == FlushTT ) {
+ int writeSize = idx * sizeof(struct pzTrace_s);
+ PR_Lock(ttLock);
+ PR_Write( ttfd, tt, writeSize );
+ traceIndex = -1;
+ PR_NotifyAllCondVar( ttCVar );
+ PR_Unlock(ttLock);
+ goto RetryTrace;
+ } else {
+ PR_Lock(ttLock);
+ while( NUM_TT_ENTRIES < idx )
+ PR_WaitCondVar(ttCVar, PR_INTERVAL_NO_WAIT);
+ PR_Unlock(ttLock);
+ goto RetryTrace;
+ }
+ } /* end while() */
+
+ /* create the trace entry */
+ tp = tt + idx;
+ tp->threadID = PR_GetThreadID(PR_GetCurrentThread());
+ tp->op = op;
+ tp->ltype = ltype;
+ tp->callTime = callTime;
+ tp->heldTime = heldTime;
+ tp->lock = lock;
+ tp ->line = line;
+ strcpy(tp->file, file );
+ return;
+} /* --- end Vtrace() --- */
+
+/*
+** pz_TraceFlush() -- Force trace table write to file
+**
+*/
+extern void pz_TraceFlush( void )
+{
+ Vtrace( FlushTT, nssILockSelfServ, 0, 0, NULL, 0, "" );
+ return;
+} /* --- end pz_TraceFlush() --- */
+
+/*
+** nssILockInit() -- Initialization for nssilock
+**
+** This function is called from the CallOnce mechanism.
+*/
+static PRStatus
+ nssILockInit( void )
+{
+ int i;
+ nssILockInitialized = 1;
+
+ /* new log module */
+ nssILog = PR_NewLogModule("nssilock");
+ if ( NULL == nssILog ) {
+ return(PR_FAILURE);
+ }
+
+ tt = PR_Calloc( NUM_TT_ENTRIES, sizeof(struct pzTrace_s));
+ if (NULL == tt ) {
+ fprintf(stderr, "nssilock: can't allocate trace table\n");
+ exit(1);
+ }
+
+ ttfd = PR_Open( "xxxTTLog", PR_CREATE_FILE | PR_WRONLY, 0666 );
+ if ( NULL == ttfd ) {
+ fprintf( stderr, "Oh Drat! Can't open 'xxxTTLog'\n");
+ exit(1);
+ }
+
+ ttLock = PR_NewLock();
+ ttCVar = PR_NewCondVar(ttLock);
+
+ return(PR_SUCCESS);
+} /* --- end nssILockInit() --- */
+
+extern PZLock * pz_NewLock(
+ nssILockType ltype,
+ char *file,
+ PRIntn line )
+{
+ PRStatus rc;
+ PZLock *lock;
+
+ /* Self Initialize the nssILock feature */
+ if (!nssILockInitialized) {
+ rc = PR_CallOnce( &coNssILock, nssILockInit );
+ if ( PR_FAILURE == rc ) {
+ PR_SetError( PR_UNKNOWN_ERROR, 0 );
+ return( NULL );
+ }
+ }
+
+ lock = PR_NEWZAP( PZLock );
+ if ( NULL != lock ) {
+ lock->ltype = ltype;
+ lock->lock = PR_NewLock();
+ if ( NULL == lock->lock ) {
+ PR_DELETE( lock );
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ } else {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ Vtrace( NewLock, ltype, 0, 0, lock, line, file );
+ return(lock);
+} /* --- end pz_NewLock() --- */
+
+extern void
+ pz_Lock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ PR_Lock( lock->lock );
+ lock->time = PR_IntervalNow();
+ callTime = lock->time - callTime;
+
+ Vtrace( Lock, lock->ltype, callTime, 0, lock, line, file );
+ return;
+} /* --- end pz_Lock() --- */
+
+extern PRStatus
+ pz_Unlock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime, now, heldTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_Unlock( lock->lock );
+ now = PR_IntervalNow();
+ callTime = now - callTime;
+ heldTime = now - lock->time;
+ Vtrace( Unlock, lock->ltype, callTime, heldTime, lock, line, file );
+ return( rc );
+} /* --- end pz_Unlock() --- */
+
+extern void
+ pz_DestroyLock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ Vtrace( DestroyLock, lock->ltype, 0, 0, lock, line, file );
+ PR_DestroyLock( lock->lock );
+ PR_DELETE( lock );
+ return;
+} /* --- end pz_DestroyLock() --- */
+
+
+
+extern PZCondVar *
+ pz_NewCondVar(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ PZCondVar *cvar;
+
+ cvar = PR_NEWZAP( PZCondVar );
+ if ( NULL == cvar ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ } else {
+ cvar->ltype = lock->ltype;
+ cvar->cvar = PR_NewCondVar( lock->lock );
+ if ( NULL == cvar->cvar ) {
+ PR_DELETE( cvar );
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ }
+ Vtrace( NewCondVar, lock->ltype, 0, 0, cvar, line, file );
+ return( cvar );
+} /* --- end pz_NewCondVar() --- */
+
+extern void
+ pz_DestroyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ )
+{
+ Vtrace( DestroyCondVar, cvar->ltype, 0, 0, cvar, line, file );
+ PR_DestroyCondVar( cvar->cvar );
+ PR_DELETE( cvar );
+} /* --- end pz_DestroyCondVar() --- */
+
+extern PRStatus
+ pz_WaitCondVar(
+ PZCondVar *cvar,
+ PRIntervalTime timeout,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_WaitCondVar( cvar->cvar, timeout );
+ callTime = PR_IntervalNow() - callTime;
+
+ Vtrace( WaitCondVar, cvar->ltype, callTime, 0, cvar, line, file );
+ return(rc);
+} /* --- end pz_WaitCondVar() --- */
+
+extern PRStatus
+ pz_NotifyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+
+ rc = PR_NotifyCondVar( cvar->cvar );
+
+ Vtrace( NotifyCondVar, cvar->ltype, 0, 0, cvar, line, file );
+ return(rc);
+} /* --- end pz_NotifyCondVar() --- */
+
+extern PRStatus
+ pz_NotifyAllCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+
+ rc = PR_NotifyAllCondVar( cvar->cvar );
+
+ Vtrace( NotifyAllCondVar, cvar->ltype, 0, 0, cvar, line, file );
+ return(rc);
+} /* --- end pz_NotifyAllCondVar() --- */
+
+extern PZMonitor *
+ pz_NewMonitor(
+ nssILockType ltype,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PZMonitor *mon;
+
+ /* Self Initialize the nssILock feature */
+ if (!nssILockInitialized) {
+ rc = PR_CallOnce( &coNssILock, nssILockInit );
+ if ( PR_FAILURE == rc ) {
+ PR_SetError( PR_UNKNOWN_ERROR, 0 );
+ return( NULL );
+ }
+ }
+
+ mon = PR_NEWZAP( PZMonitor );
+ if ( NULL != mon ) {
+ mon->ltype = ltype;
+ mon->mon = PR_NewMonitor();
+ if ( NULL == mon->mon ) {
+ PR_DELETE( mon );
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ } else {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ Vtrace( NewMonitor, ltype, 0, 0, mon, line, file );
+ return(mon);
+} /* --- end pz_NewMonitor() --- */
+
+extern void
+ pz_DestroyMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ Vtrace( DestroyMonitor, mon->ltype, 0, 0, mon, line, file );
+ PR_DestroyMonitor( mon->mon );
+ PR_DELETE( mon );
+ return;
+} /* --- end pz_DestroyMonitor() --- */
+
+extern void
+ pz_EnterMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRIntervalTime callTime, now;
+
+ callTime = PR_IntervalNow();
+ PR_EnterMonitor( mon->mon );
+ now = PR_IntervalNow();
+ callTime = now - callTime;
+ if ( PR_GetMonitorEntryCount(mon->mon) == 1 ) {
+ mon->time = now;
+ }
+ Vtrace( EnterMonitor, mon->ltype, callTime, 0, mon, line, file );
+ return;
+} /* --- end pz_EnterMonitor() --- */
+
+extern PRStatus
+ pz_ExitMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime, now, heldTime;
+ PRIntn mec = PR_GetMonitorEntryCount( mon->mon );
+
+ heldTime = (PRIntervalTime)-1;
+ callTime = PR_IntervalNow();
+ rc = PR_ExitMonitor( mon->mon );
+ now = PR_IntervalNow();
+ callTime = now - callTime;
+ if ( mec == 1 )
+ heldTime = now - mon->time;
+ Vtrace( ExitMonitor, mon->ltype, callTime, heldTime, mon, line, file );
+ return( rc );
+} /* --- end pz_ExitMonitor() --- */
+
+extern PRIntn
+ pz_GetMonitorEntryCount(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ return( PR_GetMonitorEntryCount(mon->mon));
+} /* --- end pz_GetMonitorEntryCount() --- */
+
+
+extern PRStatus
+ pz_Wait(
+ PZMonitor *mon,
+ PRIntervalTime ticks,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_Wait( mon->mon, ticks );
+ callTime = PR_IntervalNow() - callTime;
+ Vtrace( Wait, mon->ltype, callTime, 0, mon, line, file );
+ return( rc );
+} /* --- end pz_Wait() --- */
+
+extern PRStatus
+ pz_Notify(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_Notify( mon->mon );
+ callTime = PR_IntervalNow() - callTime;
+ Vtrace( Notify, mon->ltype, callTime, 0, mon, line, file );
+ return( rc );
+} /* --- end pz_Notify() --- */
+
+extern PRStatus
+ pz_NotifyAll(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_NotifyAll( mon->mon );
+ callTime = PR_IntervalNow() - callTime;
+ Vtrace( NotifyAll, mon->ltype, callTime, 0, mon, line, file );
+ return( rc );
+} /* --- end pz_NotifyAll() --- */
+
+#endif /* NEED_NSS_ILOCK */
+/* --- end nssilock.c --------------------------------- */
diff --git a/lib/util/nssilock.h b/lib/util/nssilock.h
new file mode 100644
index 000000000..a796e4afa
--- /dev/null
+++ b/lib/util/nssilock.h
@@ -0,0 +1,288 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** nssilock.h - Instrumented locking functions for NSS
+**
+** Description:
+** nssilock provides instrumentation for locks and monitors in
+** the NSS libraries. The instrumentation, when enabled, causes
+** each call to the instrumented function to record data about
+** the call to an external file. The external file
+** subsequently used to extract performance data and other
+** statistical information about the operation of locks used in
+** the nss library.
+**
+** To enable compilation with instrumentation, build NSS with
+** the compile time switch NEED_NSS_ILOCK defined.
+**
+** say: "gmake OS_CFLAGS+=-DNEED_NSS_ILOCK" at make time.
+**
+** At runtime, to enable recording from nssilock, one or more
+** environment variables must be set. For each nssILockType to
+** be recorded, an environment variable of the form NSS_ILOCK_x
+** must be set to 1. For example:
+**
+** set NSS_ILOCK_Cert=1
+**
+** nssilock uses PRLOG is used to record to trace data. The
+** PRLogModule name associated with nssilock data is: "nssilock".
+** To enable recording of nssilock data you will need to set the
+** environment variable NSPR_LOG_MODULES to enable
+** recording for the nssilock log module. Similarly, you will
+** need to set the environment variable NSPR_LOG_FILE to specify
+** the filename to receive the recorded data. See prlog.h for usage.
+** Example:
+**
+** export NSPR_LOG_MODULES=nssilock:6
+** export NSPR_LOG_FILE=xxxLogfile
+**
+** Operation:
+** nssilock wraps calls to NSPR's PZLock and PZMonitor functions
+** with similarly named functions: PZ_NewLock(), etc. When NSS is
+** built with lock instrumentation enabled, the PZ* functions are
+** compiled into NSS; when lock instrumentation is disabled,
+** calls to PZ* functions are directly mapped to PR* functions
+** and the instrumentation arguments to the PZ* functions are
+** compiled away.
+**
+**
+** File Format:
+** The format of the external file is implementation
+** dependent. Where NSPR's PR_LOG() function is used, the file
+** contains data defined for PR_LOG() plus the data written by
+** the wrapped function. On some platforms and under some
+** circumstances, platform dependent logging or
+** instrumentation probes may be used. In any case, the
+** relevant data provided by the lock instrumentation is:
+**
+** lockType, func, address, duration, line, file [heldTime]
+**
+** where:
+**
+** lockType: a character representation of nssILockType for the
+** call. e.g. ... "cert"
+**
+** func: the function doing the tracing. e.g. "NewLock"
+**
+** address: address of the instrumented lock or monitor
+**
+** duration: is how long was spent in the instrumented function,
+** in PRIntervalTime "ticks".
+**
+** line: the line number within the calling function
+**
+** file: the file from which the call was made
+**
+** heldTime: how long the lock/monitor was held. field
+** present only for PZ_Unlock() and PZ_ExitMonitor().
+**
+** Design Notes:
+** The design for lock instrumentation was influenced by the
+** need to gather performance data on NSS 3.x. It is intended
+** that the effort to modify NSS to use lock instrumentation
+** be minimized. Existing calls to locking functions need only
+** have their names changed to the instrumentation function
+** names.
+**
+** Private NSS Interface:
+** nssilock.h defines a private interface for use by NSS.
+** nssilock.h is experimental in nature and is subject to
+** change or revocation without notice. ... Don't mess with
+** it.
+**
+*/
+
+/*
+ * $Id:
+ */
+
+#ifndef _NSSILOCK_H_
+#define _NSSILOCK_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "prmon.h"
+#include "prlock.h"
+#include "prcvar.h"
+
+#include "nssilckt.h"
+
+PR_BEGIN_EXTERN_C
+
+#if defined(NEED_NSS_ILOCK)
+
+#define PZ_NewLock(t) pz_NewLock((t),__FILE__,__LINE__)
+extern PZLock *
+ pz_NewLock(
+ nssILockType ltype,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Lock(k) pz_Lock((k),__FILE__,__LINE__)
+extern void
+ pz_Lock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Unlock(k) pz_Unlock((k),__FILE__,__LINE__)
+extern PRStatus
+ pz_Unlock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_DestroyLock(k) pz_DestroyLock((k),__FILE__,__LINE__)
+extern void
+ pz_DestroyLock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+
+#define PZ_NewCondVar(l) pz_NewCondVar((l),__FILE__,__LINE__)
+extern PZCondVar *
+ pz_NewCondVar(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_DestroyCondVar(v) pz_DestroyCondVar((v),__FILE__,__LINE__)
+extern void
+ pz_DestroyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_WaitCondVar(v,t) pz_WaitCondVar((v),(t),__FILE__,__LINE__)
+extern PRStatus
+ pz_WaitCondVar(
+ PZCondVar *cvar,
+ PRIntervalTime timeout,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_NotifyCondVar(v) pz_NotifyCondVar((v),__FILE__,__LINE__)
+extern PRStatus
+ pz_NotifyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_NotifyAllCondVar(v) pz_NotifyAllCondVar((v),__FILE__,__LINE__)
+extern PRStatus
+ pz_NotifyAllCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ );
+
+
+#define PZ_NewMonitor(t) pz_NewMonitor((t),__FILE__,__LINE__)
+extern PZMonitor *
+ pz_NewMonitor(
+ nssILockType ltype,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_DestroyMonitor(m) pz_DestroyMonitor((m),__FILE__,__LINE__)
+extern void
+ pz_DestroyMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_EnterMonitor(m) pz_EnterMonitor((m),__FILE__,__LINE__)
+extern void
+ pz_EnterMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+
+#define PZ_ExitMonitor(m) pz_ExitMonitor((m),__FILE__,__LINE__)
+extern PRStatus
+ pz_ExitMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_InMonitor(m) (PZ_GetMonitorEntryCount(m) > 0 )
+#define PZ_GetMonitorEntryCount(m) pz_GetMonitorEntryCount((m),__FILE__,__LINE__)
+extern PRIntn
+ pz_GetMonitorEntryCount(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Wait(m,i) pz_Wait((m),((i)),__FILE__,__LINE__)
+extern PRStatus
+ pz_Wait(
+ PZMonitor *mon,
+ PRIntervalTime ticks,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Notify(m) pz_Notify((m),__FILE__,__LINE__)
+extern PRStatus
+ pz_Notify(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_NotifyAll(m) pz_NotifyAll((m),__FILE__,__LINE__)
+extern PRStatus
+ pz_NotifyAll(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_TraceFlush() pz_TraceFlush()
+extern void pz_TraceFlush( void );
+
+#else /* NEED_NSS_ILOCK */
+
+#define PZ_NewLock(t) PR_NewLock()
+#define PZ_DestroyLock(k) PR_DestroyLock((k))
+#define PZ_Lock(k) PR_Lock((k))
+#define PZ_Unlock(k) PR_Unlock((k))
+
+#define PZ_NewCondVar(l) PR_NewCondVar((l))
+#define PZ_DestroyCondVar(v) PR_DestroyCondVar((v))
+#define PZ_WaitCondVar(v,t) PR_WaitCondVar((v),(t))
+#define PZ_NotifyCondVar(v) PR_NotifyCondVar((v))
+#define PZ_NotifyAllCondVar(v) PR_NotifyAllCondVar((v))
+
+#define PZ_NewMonitor(t) PR_NewMonitor()
+#define PZ_DestroyMonitor(m) PR_DestroyMonitor((m))
+#define PZ_EnterMonitor(m) PR_EnterMonitor((m))
+#define PZ_ExitMonitor(m) PR_ExitMonitor((m))
+#define PZ_InMonitor(m) PR_InMonitor((m))
+#define PZ_Wait(m,t) PR_Wait(((m)),((t)))
+#define PZ_Notify(m) PR_Notify((m))
+#define PZ_NotifyAll(m) PR_Notify((m))
+#define PZ_TraceFlush() /* nothing */
+
+
+#endif /* NEED_NSS_ILOCK */
+
+PR_END_EXTERN_C
+#endif /* _NSSILOCK_H_ */
diff --git a/lib/util/nsslocks.h b/lib/util/nsslocks.h
new file mode 100644
index 000000000..e294285c3
--- /dev/null
+++ b/lib/util/nsslocks.h
@@ -0,0 +1,13 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * nsslocks.h - threadsafe functions to initialize lock pointers.
+ *
+ * NOTE - The interfaces formerly in this header were private and are now all
+ * obsolete.
+ *
+ * $Id$
+ */
+
diff --git a/lib/util/nssrwlk.c b/lib/util/nssrwlk.c
new file mode 100644
index 000000000..65fceda2e
--- /dev/null
+++ b/lib/util/nssrwlk.c
@@ -0,0 +1,447 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nssrwlk.h"
+#include "nspr.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Reader-writer lock
+ */
+struct nssRWLockStr {
+ PZLock * rw_lock;
+ char * rw_name; /* lock name */
+ PRUint32 rw_rank; /* rank of the lock */
+ PRInt32 rw_writer_locks; /* == 0, if unlocked */
+ PRInt32 rw_reader_locks; /* == 0, if unlocked */
+ /* > 0 , # of read locks */
+ PRUint32 rw_waiting_readers; /* number of waiting readers */
+ PRUint32 rw_waiting_writers; /* number of waiting writers */
+ PZCondVar * rw_reader_waitq; /* cvar for readers */
+ PZCondVar * rw_writer_waitq; /* cvar for writers */
+ PRThread * rw_owner; /* lock owner for write-lock */
+ /* Non-null if write lock held. */
+};
+
+PR_END_EXTERN_C
+
+#include <string.h>
+
+#ifdef DEBUG_RANK_ORDER
+#define NSS_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using
+ rank-order for locks
+ */
+#endif
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+static PRUintn nss_thread_rwlock_initialized;
+static PRUintn nss_thread_rwlock; /* TPD key for lock stack */
+static PRUintn nss_thread_rwlock_alloc_failed;
+
+#define _NSS_RWLOCK_RANK_ORDER_LIMIT 10
+
+typedef struct thread_rwlock_stack {
+ PRInt32 trs_index; /* top of stack */
+ NSSRWLock *trs_stack[_NSS_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock
+ pointers */
+} thread_rwlock_stack;
+
+/* forward static declarations. */
+static PRUint32 nssRWLock_GetThreadRank(PRThread *me);
+static void nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock);
+static void nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock);
+static void nssRWLock_ReleaseLockStack(void *lock_stack);
+
+#endif
+
+#define UNTIL(x) while(!(x))
+
+/*
+ * Reader/Writer Locks
+ */
+
+/*
+ * NSSRWLock_New
+ * Create a reader-writer lock, with the given lock rank and lock name
+ *
+ */
+
+NSSRWLock *
+NSSRWLock_New(PRUint32 lock_rank, const char *lock_name)
+{
+ NSSRWLock *rwlock;
+
+ rwlock = PR_NEWZAP(NSSRWLock);
+ if (rwlock == NULL)
+ return NULL;
+
+ rwlock->rw_lock = PZ_NewLock(nssILockRWLock);
+ if (rwlock->rw_lock == NULL) {
+ goto loser;
+ }
+ rwlock->rw_reader_waitq = PZ_NewCondVar(rwlock->rw_lock);
+ if (rwlock->rw_reader_waitq == NULL) {
+ goto loser;
+ }
+ rwlock->rw_writer_waitq = PZ_NewCondVar(rwlock->rw_lock);
+ if (rwlock->rw_writer_waitq == NULL) {
+ goto loser;
+ }
+ if (lock_name != NULL) {
+ rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
+ if (rwlock->rw_name == NULL) {
+ goto loser;
+ }
+ strcpy(rwlock->rw_name, lock_name);
+ } else {
+ rwlock->rw_name = NULL;
+ }
+ rwlock->rw_rank = lock_rank;
+ rwlock->rw_waiting_readers = 0;
+ rwlock->rw_waiting_writers = 0;
+ rwlock->rw_reader_locks = 0;
+ rwlock->rw_writer_locks = 0;
+
+ return rwlock;
+
+loser:
+ NSSRWLock_Destroy(rwlock);
+ return(NULL);
+}
+
+/*
+** Destroy the given RWLock "lock".
+*/
+void
+NSSRWLock_Destroy(NSSRWLock *rwlock)
+{
+ PR_ASSERT(rwlock != NULL);
+ PR_ASSERT(rwlock->rw_waiting_readers == 0);
+
+ /* XXX Shouldn't we lock the PZLock before destroying this?? */
+
+ if (rwlock->rw_name)
+ PR_Free(rwlock->rw_name);
+ if (rwlock->rw_reader_waitq)
+ PZ_DestroyCondVar(rwlock->rw_reader_waitq);
+ if (rwlock->rw_writer_waitq)
+ PZ_DestroyCondVar(rwlock->rw_writer_waitq);
+ if (rwlock->rw_lock)
+ PZ_DestroyLock(rwlock->rw_lock);
+ PR_DELETE(rwlock);
+}
+
+/*
+** Read-lock the RWLock.
+*/
+void
+NSSRWLock_LockRead(NSSRWLock *rwlock)
+{
+ PRThread *me = PR_GetCurrentThread();
+
+ PZ_Lock(rwlock->rw_lock);
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+ /*
+ * assert that rank ordering is not violated; the rank of 'rwlock' should
+ * be equal to or greater than the highest rank of all the locks held by
+ * the thread.
+ */
+ PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
+ (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
+#endif
+ /*
+ * wait if write-locked or if a writer is waiting; preference for writers
+ */
+ UNTIL ( (rwlock->rw_owner == me) || /* I own it, or */
+ ((rwlock->rw_owner == NULL) && /* no-one owns it, and */
+ (rwlock->rw_waiting_writers == 0))) { /* no-one is waiting to own */
+
+ rwlock->rw_waiting_readers++;
+ PZ_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
+ rwlock->rw_waiting_readers--;
+ }
+ rwlock->rw_reader_locks++; /* Increment read-lock count */
+
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ nssRWLock_SetThreadRank(me, rwlock);/* update thread's lock rank */
+#endif
+}
+
+/* Unlock a Read lock held on this RW lock.
+*/
+void
+NSSRWLock_UnlockRead(NSSRWLock *rwlock)
+{
+ PZ_Lock(rwlock->rw_lock);
+
+ PR_ASSERT(rwlock->rw_reader_locks > 0); /* lock must be read locked */
+
+ if (( rwlock->rw_reader_locks > 0) && /* caller isn't screwey */
+ (--rwlock->rw_reader_locks == 0) && /* not read locked any more */
+ ( rwlock->rw_owner == NULL) && /* not write locked */
+ ( rwlock->rw_waiting_writers > 0)) { /* someone's waiting. */
+
+ PZ_NotifyCondVar(rwlock->rw_writer_waitq); /* wake him up. */
+ }
+
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * update thread's lock rank
+ */
+ nssRWLock_UnsetThreadRank(me, rwlock);
+#endif
+ return;
+}
+
+/*
+** Write-lock the RWLock.
+*/
+void
+NSSRWLock_LockWrite(NSSRWLock *rwlock)
+{
+ PRThread *me = PR_GetCurrentThread();
+
+ PZ_Lock(rwlock->rw_lock);
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * assert that rank ordering is not violated; the rank of 'rwlock' should
+ * be equal to or greater than the highest rank of all the locks held by
+ * the thread.
+ */
+ PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
+ (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
+#endif
+ /*
+ * wait if read locked or write locked.
+ */
+ PR_ASSERT(rwlock->rw_reader_locks >= 0);
+ PR_ASSERT(me != NULL);
+
+ UNTIL ( (rwlock->rw_owner == me) || /* I own write lock, or */
+ ((rwlock->rw_owner == NULL) && /* no writer and */
+ (rwlock->rw_reader_locks == 0))) { /* no readers, either. */
+
+ rwlock->rw_waiting_writers++;
+ PZ_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
+ rwlock->rw_waiting_writers--;
+ PR_ASSERT(rwlock->rw_reader_locks >= 0);
+ }
+
+ PR_ASSERT(rwlock->rw_reader_locks == 0);
+ /*
+ * apply write lock
+ */
+ rwlock->rw_owner = me;
+ rwlock->rw_writer_locks++; /* Increment write-lock count */
+
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * update thread's lock rank
+ */
+ nssRWLock_SetThreadRank(me,rwlock);
+#endif
+}
+
+/* Unlock a Read lock held on this RW lock.
+*/
+void
+NSSRWLock_UnlockWrite(NSSRWLock *rwlock)
+{
+ PRThread *me = PR_GetCurrentThread();
+
+ PZ_Lock(rwlock->rw_lock);
+ PR_ASSERT(rwlock->rw_owner == me); /* lock must be write-locked by me. */
+ PR_ASSERT(rwlock->rw_writer_locks > 0); /* lock must be write locked */
+
+ if ( rwlock->rw_owner == me && /* I own it, and */
+ rwlock->rw_writer_locks > 0 && /* I own it, and */
+ --rwlock->rw_writer_locks == 0) { /* I'm all done with it */
+
+ rwlock->rw_owner = NULL; /* I don't own it any more. */
+
+ /* Give preference to waiting writers. */
+ if (rwlock->rw_waiting_writers > 0) {
+ if (rwlock->rw_reader_locks == 0)
+ PZ_NotifyCondVar(rwlock->rw_writer_waitq);
+ } else if (rwlock->rw_waiting_readers > 0) {
+ PZ_NotifyAllCondVar(rwlock->rw_reader_waitq);
+ }
+ }
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * update thread's lock rank
+ */
+ nssRWLock_UnsetThreadRank(me, rwlock);
+#endif
+ return;
+}
+
+/* This is primarily for debugging, i.e. for inclusion in ASSERT calls. */
+PRBool
+NSSRWLock_HaveWriteLock(NSSRWLock *rwlock) {
+ PRBool ownWriteLock;
+ PRThread *me = PR_GetCurrentThread();
+
+ /* This lock call isn't really necessary.
+ ** If this thread is the owner, that fact cannot change during this call,
+ ** because this thread is in this call.
+ ** If this thread is NOT the owner, the owner could change, but it
+ ** could not become this thread.
+ */
+#if UNNECESSARY
+ PZ_Lock(rwlock->rw_lock);
+#endif
+ ownWriteLock = (PRBool)(me == rwlock->rw_owner);
+#if UNNECESSARY
+ PZ_Unlock(rwlock->rw_lock);
+#endif
+ return ownWriteLock;
+}
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+/*
+ * nssRWLock_SetThreadRank
+ * Set a thread's lock rank, which is the highest of the ranks of all
+ * the locks held by the thread. Pointers to the locks are added to a
+ * per-thread list, which is anchored off a thread-private data key.
+ */
+
+static void
+nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock)
+{
+ thread_rwlock_stack *lock_stack;
+ PRStatus rv;
+
+ /*
+ * allocated thread-private-data for rwlock list, if not already allocated
+ */
+ if (!nss_thread_rwlock_initialized) {
+ /*
+ * allocate tpd, only if not failed already
+ */
+ if (!nss_thread_rwlock_alloc_failed) {
+ if (PR_NewThreadPrivateIndex(&nss_thread_rwlock,
+ nssRWLock_ReleaseLockStack)
+ == PR_FAILURE) {
+ nss_thread_rwlock_alloc_failed = 1;
+ return;
+ }
+ } else
+ return;
+ }
+ /*
+ * allocate a lock stack
+ */
+ if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL) {
+ lock_stack = (thread_rwlock_stack *)
+ PR_CALLOC(1 * sizeof(thread_rwlock_stack));
+ if (lock_stack) {
+ rv = PR_SetThreadPrivate(nss_thread_rwlock, lock_stack);
+ if (rv == PR_FAILURE) {
+ PR_DELETE(lock_stack);
+ nss_thread_rwlock_alloc_failed = 1;
+ return;
+ }
+ } else {
+ nss_thread_rwlock_alloc_failed = 1;
+ return;
+ }
+ }
+ /*
+ * add rwlock to lock stack, if limit is not exceeded
+ */
+ if (lock_stack) {
+ if (lock_stack->trs_index < _NSS_RWLOCK_RANK_ORDER_LIMIT)
+ lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;
+ }
+ nss_thread_rwlock_initialized = 1;
+}
+
+static void
+nssRWLock_ReleaseLockStack(void *lock_stack)
+{
+ PR_ASSERT(lock_stack);
+ PR_DELETE(lock_stack);
+}
+
+/*
+ * nssRWLock_GetThreadRank
+ *
+ * return thread's lock rank. If thread-private-data for the lock
+ * stack is not allocated, return NSS_RWLOCK_RANK_NONE.
+ */
+
+static PRUint32
+nssRWLock_GetThreadRank(PRThread *me)
+{
+ thread_rwlock_stack *lock_stack;
+
+ if (nss_thread_rwlock_initialized) {
+ if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL)
+ return (NSS_RWLOCK_RANK_NONE);
+ else
+ return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
+
+ } else
+ return (NSS_RWLOCK_RANK_NONE);
+}
+
+/*
+ * nssRWLock_UnsetThreadRank
+ *
+ * remove the rwlock from the lock stack. Since locks may not be
+ * unlocked in a FIFO order, the entire lock stack is searched.
+ */
+
+static void
+nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock)
+{
+ thread_rwlock_stack *lock_stack;
+ int new_index = 0, index, done = 0;
+
+ if (!nss_thread_rwlock_initialized)
+ return;
+
+ lock_stack = PR_GetThreadPrivate(nss_thread_rwlock);
+
+ PR_ASSERT(lock_stack != NULL);
+
+ index = lock_stack->trs_index - 1;
+ while (index-- >= 0) {
+ if ((lock_stack->trs_stack[index] == rwlock) && !done) {
+ /*
+ * reset the slot for rwlock
+ */
+ lock_stack->trs_stack[index] = NULL;
+ done = 1;
+ }
+ /*
+ * search for the lowest-numbered empty slot, above which there are
+ * no non-empty slots
+ */
+ if ((lock_stack->trs_stack[index] != NULL) && !new_index)
+ new_index = index + 1;
+ if (done && new_index)
+ break;
+ }
+ /*
+ * set top of stack to highest numbered empty slot
+ */
+ lock_stack->trs_index = new_index;
+
+}
+
+#endif /* NSS_RWLOCK_RANK_ORDER_DEBUG */
diff --git a/lib/util/nssrwlk.h b/lib/util/nssrwlk.h
new file mode 100644
index 000000000..3402c82e1
--- /dev/null
+++ b/lib/util/nssrwlk.h
@@ -0,0 +1,132 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+** File: nsrwlock.h
+** Description: API to basic reader-writer lock functions of NSS.
+** These are re-entrant reader writer locks; that is,
+** If I hold the write lock, I can ask for it and get it again.
+** If I hold the write lock, I can also ask for and get a read lock.
+** I can then release the locks in any order (read or write).
+** I must release each lock type as many times as I acquired it.
+** Otherwise, these are normal reader/writer locks.
+**
+** For deadlock detection, locks should be ranked, and no lock may be aquired
+** while I hold a lock of higher rank number.
+** If you don't want that feature, always use NSS_RWLOCK_RANK_NONE.
+** Lock name is for debugging, and is optional (may be NULL)
+**/
+
+#ifndef nssrwlk_h___
+#define nssrwlk_h___
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "nssrwlkt.h"
+
+#define NSS_RWLOCK_RANK_NONE 0
+
+/* SEC_BEGIN_PROTOS */
+PR_BEGIN_EXTERN_C
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_New
+** DESCRIPTION:
+** Returns a pointer to a newly created reader-writer lock object.
+** INPUTS: Lock rank
+** Lock name
+** OUTPUTS: void
+** RETURN: NSSRWLock*
+** If the lock cannot be created because of resource constraints, NULL
+** is returned.
+**
+***********************************************************************/
+extern NSSRWLock* NSSRWLock_New(PRUint32 lock_rank, const char *lock_name);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_AtomicCreate
+** DESCRIPTION:
+** Given the address of a NULL pointer to a NSSRWLock,
+** atomically initializes that pointer to a newly created NSSRWLock.
+** Returns the value placed into that pointer, or NULL.
+**
+** INPUTS: address of NSRWLock pointer
+** Lock rank
+** Lock name
+** OUTPUTS: NSSRWLock*
+** RETURN: NSSRWLock*
+** If the lock cannot be created because of resource constraints,
+** the pointer will be left NULL.
+**
+***********************************************************************/
+extern NSSRWLock *
+nssRWLock_AtomicCreate( NSSRWLock ** prwlock,
+ PRUint32 lock_rank,
+ const char * lock_name);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_Destroy
+** DESCRIPTION:
+** Destroys a given RW lock object.
+** INPUTS: NSSRWLock *lock - Lock to be freed.
+** OUTPUTS: void
+** RETURN: None
+***********************************************************************/
+extern void NSSRWLock_Destroy(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_LockRead
+** DESCRIPTION:
+** Apply a read lock (non-exclusive) on a RWLock
+** INPUTS: NSSRWLock *lock - Lock to be read-locked.
+** OUTPUTS: void
+** RETURN: None
+***********************************************************************/
+extern void NSSRWLock_LockRead(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_LockWrite
+** DESCRIPTION:
+** Apply a write lock (exclusive) on a RWLock
+** INPUTS: NSSRWLock *lock - Lock to write-locked.
+** OUTPUTS: void
+** RETURN: None
+***********************************************************************/
+extern void NSSRWLock_LockWrite(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_UnlockRead
+** DESCRIPTION:
+** Release a Read lock. Unlocking an unlocked lock has undefined results.
+** INPUTS: NSSRWLock *lock - Lock to unlocked.
+** OUTPUTS: void
+** RETURN: void
+***********************************************************************/
+extern void NSSRWLock_UnlockRead(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_UnlockWrite
+** DESCRIPTION:
+** Release a Write lock. Unlocking an unlocked lock has undefined results.
+** INPUTS: NSSRWLock *lock - Lock to unlocked.
+** OUTPUTS: void
+** RETURN: void
+***********************************************************************/
+extern void NSSRWLock_UnlockWrite(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_HaveWriteLock
+** DESCRIPTION:
+** Tells caller whether the current thread holds the write lock, or not.
+** INPUTS: NSSRWLock *lock - Lock to test.
+** OUTPUTS: void
+** RETURN: PRBool PR_TRUE IFF the current thread holds the write lock.
+***********************************************************************/
+
+extern PRBool NSSRWLock_HaveWriteLock(NSSRWLock *rwlock);
+
+/* SEC_END_PROTOS */
+PR_END_EXTERN_C
+
+#endif /* nsrwlock_h___ */
diff --git a/lib/util/nssrwlkt.h b/lib/util/nssrwlkt.h
new file mode 100644
index 000000000..57251035f
--- /dev/null
+++ b/lib/util/nssrwlkt.h
@@ -0,0 +1,20 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nssrwlkt_h___
+#define nssrwlkt_h___
+
+#include "utilrename.h"
+#include "nssilock.h"
+/*
+ * NSSRWLock --
+ *
+ * The reader writer lock, NSSRWLock, is an opaque object to the clients
+ * of NSS. All routines operate on a pointer to this opaque entity.
+ */
+
+typedef struct nssRWLockStr NSSRWLock;
+
+
+#endif /* nsrwlock_h___ */
diff --git a/lib/util/nssutil.def b/lib/util/nssutil.def
new file mode 100644
index 000000000..b7a94b219
--- /dev/null
+++ b/lib/util/nssutil.def
@@ -0,0 +1,272 @@
+;+#
+;+# This Source Code Form is subject to the terms of the Mozilla Public
+;+# License, v. 2.0. If a copy of the MPL was not distributed with this
+;+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;+#
+;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS
+;+# 1. For all unix platforms, the string ";-" means "remove this line"
+;+# 2. For all unix platforms, the string " DATA " will be removed from any
+;+# line on which it occurs.
+;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
+;+# On AIX, lines containing ";+" will be removed.
+;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed.
+;+# 5. For all unix platforms, after the above processing has taken place,
+;+# all characters after the first ";" on the line will be removed.
+;+# And for AIX, the first ";" will also be removed.
+;+# This file is passed directly to windows. Since ';' is a comment, all UNIX
+;+# directives are hidden behind ";", ";+", and ";-"
+;+NSSUTIL_3.12 { # NSS Utilities 3.12 release
+;+ global:
+LIBRARY nssutil3 ;-
+EXPORTS ;-
+ATOB_AsciiToData_Util;
+ATOB_ConvertAsciiToItem_Util;
+BTOA_ConvertItemToAscii_Util;
+BTOA_DataToAscii_Util;
+CERT_GenTime2FormattedAscii_Util;
+DER_AsciiToTime_Util;
+DER_DecodeTimeChoice_Util;
+DER_Encode_Util;
+DER_EncodeTimeChoice_Util;
+DER_GeneralizedDayToAscii_Util;
+DER_GeneralizedTimeToTime_Util;
+DER_GetInteger_Util;
+DER_GetUInteger;
+DER_LengthLength;
+DER_Lengths_Util;
+DER_SetUInteger;
+DER_StoreHeader;
+DER_TimeChoiceDayToAscii_Util;
+DER_TimeToGeneralizedTime_Util;
+DER_TimeToGeneralizedTimeArena_Util;
+DER_TimeToUTCTime_Util;
+DER_UTCDayToAscii_Util;
+DER_UTCTimeToAscii_Util;
+DER_UTCTimeToTime_Util;
+NSS_PutEnv_Util;
+NSSBase64_DecodeBuffer_Util;
+NSSBase64_EncodeItem_Util;
+NSSBase64Decoder_Create_Util;
+NSSBase64Decoder_Destroy_Util;
+NSSBase64Decoder_Update_Util;
+NSSBase64Encoder_Create_Util;
+NSSBase64Encoder_Destroy_Util;
+NSSBase64Encoder_Update_Util;
+NSSRWLock_Destroy_Util;
+NSSRWLock_HaveWriteLock_Util;
+NSSRWLock_LockRead_Util;
+NSSRWLock_LockWrite_Util;
+NSSRWLock_New_Util;
+NSSRWLock_UnlockRead_Util;
+NSSRWLock_UnlockWrite_Util;
+PORT_Alloc_Util;
+PORT_ArenaAlloc_Util;
+PORT_ArenaGrow_Util;
+PORT_ArenaMark_Util;
+PORT_ArenaRelease_Util;
+PORT_ArenaStrdup_Util;
+PORT_ArenaUnmark_Util;
+PORT_ArenaZAlloc_Util;
+PORT_Free_Util;
+PORT_FreeArena_Util;
+PORT_GetError_Util;
+PORT_ISO88591_UTF8Conversion;
+PORT_NewArena_Util;
+PORT_Realloc_Util;
+PORT_RegExpCaseSearch;
+PORT_RegExpValid;
+PORT_SetError_Util;
+PORT_SetUCS2_ASCIIConversionFunction_Util;
+PORT_SetUCS2_UTF8ConversionFunction_Util;
+PORT_SetUCS4_UTF8ConversionFunction_Util;
+PORT_Strdup_Util;
+PORT_UCS2_ASCIIConversion_Util;
+PORT_UCS2_UTF8Conversion_Util;
+PORT_UCS4_UTF8Conversion;
+PORT_ZAlloc_Util;
+PORT_ZFree_Util;
+SEC_ASN1Decode_Util;
+SEC_ASN1DecodeInteger_Util;
+SEC_ASN1DecodeItem_Util;
+SEC_ASN1DecoderAbort_Util;
+SEC_ASN1DecoderClearFilterProc_Util;
+SEC_ASN1DecoderClearNotifyProc_Util;
+SEC_ASN1DecoderFinish_Util;
+SEC_ASN1DecoderSetFilterProc_Util;
+SEC_ASN1DecoderSetNotifyProc_Util;
+SEC_ASN1DecoderStart_Util;
+SEC_ASN1DecoderUpdate_Util;
+SEC_ASN1Encode_Util;
+SEC_ASN1EncodeInteger_Util;
+SEC_ASN1EncodeItem_Util;
+SEC_ASN1EncoderAbort_Util;
+SEC_ASN1EncoderClearNotifyProc_Util;
+SEC_ASN1EncoderClearStreaming_Util;
+SEC_ASN1EncoderClearTakeFromBuf_Util;
+SEC_ASN1EncoderFinish_Util;
+SEC_ASN1EncoderSetNotifyProc_Util;
+SEC_ASN1EncoderSetStreaming_Util;
+SEC_ASN1EncoderSetTakeFromBuf_Util;
+SEC_ASN1EncoderStart_Util;
+SEC_ASN1EncoderUpdate_Util;
+SEC_ASN1EncodeUnsignedInteger_Util;
+SEC_ASN1LengthLength_Util;
+SEC_QuickDERDecodeItem_Util;
+SEC_StringToOID;
+SECITEM_AllocItem_Util;
+SECITEM_ArenaDupItem_Util;
+SECITEM_CompareItem_Util;
+SECITEM_CopyItem_Util;
+SECITEM_DupItem_Util;
+SECITEM_FreeItem_Util;
+SECITEM_Hash;
+SECITEM_HashCompare;
+SECITEM_ItemsAreEqual_Util;
+SECITEM_ZfreeItem_Util;
+SECOID_AddEntry_Util;
+SECOID_CompareAlgorithmID_Util;
+SECOID_CopyAlgorithmID_Util;
+SECOID_DestroyAlgorithmID_Util;
+SECOID_FindOID_Util;
+SECOID_FindOIDByMechanism;
+SECOID_FindOIDByTag_Util;
+SECOID_FindOIDTag_Util;
+SECOID_FindOIDTagDescription_Util;
+SECOID_GetAlgorithmTag_Util;
+SECOID_Init;
+SECOID_KnownCertExtenOID;
+SECOID_SetAlgorithmID_Util;
+SECOID_Shutdown;
+SGN_CompareDigestInfo_Util;
+SGN_CopyDigestInfo_Util;
+SGN_CreateDigestInfo_Util;
+SGN_DecodeDigestInfo;
+SGN_DestroyDigestInfo_Util;
+;+#
+;+# Data objects
+;+#
+;+# Don't export these DATA symbols on Windows because they don't work right.
+;+# Use the SEC_ASN1_GET / SEC_ASN1_SUB / SEC_ASN1_XTRN macros to access them.
+;;SEC_AnyTemplate_Util DATA ;
+;;SEC_BitStringTemplate_Util DATA ;
+;;SEC_BMPStringTemplate_Util DATA ;
+;;SEC_BooleanTemplate_Util DATA ;
+;;SEC_EnumeratedTemplate DATA ;
+;;SEC_GeneralizedTimeTemplate_Util DATA ;
+;;SEC_IA5StringTemplate_Util DATA ;
+;;SEC_IntegerTemplate_Util DATA ;
+;;SEC_NullTemplate_Util DATA ;
+;;SEC_ObjectIDTemplate_Util DATA ;
+;;SEC_OctetStringTemplate_Util DATA ;
+;;SEC_PointerToAnyTemplate_Util DATA ;
+;;SEC_PointerToEnumeratedTemplate DATA ;
+;;SEC_PointerToGeneralizedTimeTemplate DATA ;
+;;SEC_PointerToOctetStringTemplate_Util DATA ;
+;;SEC_PrintableStringTemplate DATA ;
+;;SEC_SequenceOfAnyTemplate DATA ;
+;;SEC_SequenceOfObjectIDTemplate DATA ;
+;;SEC_SetOfAnyTemplate_Util DATA ;
+;;SEC_SkipTemplate DATA ;
+;;SEC_T61StringTemplate DATA ;
+;;SEC_UniversalStringTemplate DATA ;
+;;SEC_UTF8StringTemplate_Util DATA ;
+;;SECOID_AlgorithmIDTemplate_Util DATA ;
+;;sgn_DigestInfoTemplate_Util DATA ;
+NSS_Get_SEC_AnyTemplate_Util;
+NSS_Get_SEC_BitStringTemplate_Util;
+NSS_Get_SEC_BMPStringTemplate_Util;
+NSS_Get_SEC_BooleanTemplate_Util;
+NSS_Get_SEC_EnumeratedTemplate;
+NSS_Get_SEC_GeneralizedTimeTemplate_Util;
+NSS_Get_SEC_IA5StringTemplate_Util;
+NSS_Get_SEC_IntegerTemplate_Util;
+NSS_Get_SEC_NullTemplate_Util;
+NSS_Get_SEC_ObjectIDTemplate_Util;
+NSS_Get_SEC_OctetStringTemplate_Util;
+NSS_Get_SEC_PointerToAnyTemplate_Util;
+NSS_Get_SEC_PointerToEnumeratedTemplate;
+NSS_Get_SEC_PointerToGeneralizedTimeTemplate;
+NSS_Get_SEC_PointerToOctetStringTemplate_Util;
+NSS_Get_SEC_PrintableStringTemplate;
+NSS_Get_SEC_SequenceOfAnyTemplate;
+NSS_Get_SEC_SequenceOfObjectIDTemplate;
+NSS_Get_SEC_SetOfAnyTemplate_Util;
+NSS_Get_SEC_SkipTemplate;
+NSS_Get_SEC_T61StringTemplate;
+NSS_Get_SEC_UniversalStringTemplate;
+NSS_Get_SEC_UTF8StringTemplate_Util;
+NSS_Get_SECOID_AlgorithmIDTemplate_Util;
+NSS_Get_sgn_DigestInfoTemplate_Util;
+;+ local:
+;+ *;
+;+};
+;+NSSUTIL_3.12.3 { # NSS Utilities 3.12.3 release
+;+ global:
+NSS_GetAlgorithmPolicy;
+NSS_SetAlgorithmPolicy;
+SECITEM_ReallocItem;
+UTIL_SetForkState;
+;+ local:
+;+ *;
+;+};
+;+NSSUTIL_3.12.5 { # NSS Utilities 3.12.5 release
+;+ global:
+NSS_SecureMemcmp;
+PORT_LoadLibraryFromOrigin;
+;+ local:
+;+ *;
+;+};
+;+NSSUTIL_3.12.7 { # NSS Utilities 3.12.7 release
+;+ global:
+PORT_RegExpSearch;
+;+ local:
+;+ *;
+;+};
+;+NSSUTIL_3.13 { # NSS Utilities 3.13 release
+;+ global:
+NSSUTIL_GetVersion;
+NSS_InitializePRErrorTable;
+;+ local:
+;+ *;
+;+};
+;+NSSUTIL_3.14 { # NSS Utilities 3.14 release
+;+ global:
+;+# private exports for softoken
+_NSSUTIL_GetSecmodName;
+_NSSUTIL_EvaluateConfigDir;
+;+# public exports
+NSSUTIL_ArgDecodeNumber;
+NSSUTIL_ArgFetchValue;
+NSSUTIL_ArgGetParamValue;
+NSSUTIL_ArgGetLabel;
+NSSUTIL_ArgHasFlag;
+NSSUTIL_ArgIsBlank;
+NSSUTIL_ArgParseCipherFlags;
+NSSUTIL_ArgParseModuleSpec;
+NSSUTIL_ArgParseSlotFlags;
+NSSUTIL_ArgParseSlotInfo;
+NSSUTIL_ArgReadLong;
+NSSUTIL_ArgSkipParameter;
+NSSUTIL_ArgStrip;
+NSSUTIL_DoModuleDBFunction;
+NSSUTIL_DoubleEscape;
+NSSUTIL_DoubleEscapeSize;
+NSSUTIL_Escape;
+NSSUTIL_EscapeSize;
+NSSUTIL_MkModuleSpec;
+NSSUTIL_MkNSSString;
+NSSUTIL_MkSlotString;
+NSSUTIL_Quote;
+NSSUTIL_QuoteSize;
+;+ local:
+;+ *;
+;+};
+;+NSSUTIL_3.14.2 { # NSS Utilities 3.14.2 release
+;+ global:
+SECITEM_AllocArray;
+SECITEM_DupArray;
+SECITEM_FreeArray;
+SECITEM_ZfreeArray;
+;+ local:
+;+ *;
+;+};
diff --git a/lib/util/nssutil.h b/lib/util/nssutil.h
new file mode 100644
index 000000000..a1b46bd84
--- /dev/null
+++ b/lib/util/nssutil.h
@@ -0,0 +1,41 @@
+/*
+ * NSS utility functions
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __nssutil_h_
+#define __nssutil_h_
+
+#ifndef RC_INVOKED
+#include "seccomon.h"
+#endif
+
+/*
+ * NSS utilities's major version, minor version, patch level, build number,
+ * and whether this is a beta release.
+ *
+ * The format of the version string should be
+ * "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
+ */
+#define NSSUTIL_VERSION "3.14.4.0 Beta"
+#define NSSUTIL_VMAJOR 3
+#define NSSUTIL_VMINOR 14
+#define NSSUTIL_VPATCH 4
+#define NSSUTIL_VBUILD 0
+#define NSSUTIL_BETA PR_TRUE
+
+SEC_BEGIN_PROTOS
+
+/*
+ * Returns a const string of the UTIL library version.
+ */
+extern const char *NSSUTIL_GetVersion(void);
+
+extern SECStatus
+NSS_InitializePRErrorTable(void);
+
+SEC_END_PROTOS
+
+#endif /* __nssutil_h_ */
diff --git a/lib/util/nssutil.rc b/lib/util/nssutil.rc
new file mode 100644
index 000000000..65d4e68b2
--- /dev/null
+++ b/lib/util/nssutil.rc
@@ -0,0 +1,68 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nssutil.h"
+#include <winver.h>
+
+#define MY_LIBNAME "nssutil"
+#define MY_FILEDESCRIPTION "NSS Utility Library"
+
+#define STRINGIZE(x) #x
+#define STRINGIZE2(x) STRINGIZE(x)
+#define NSSUTIL_VMAJOR_STR STRINGIZE2(NSSUTIL_VMAJOR)
+
+#ifdef _DEBUG
+#define MY_DEBUG_STR " (debug)"
+#define MY_FILEFLAGS_1 VS_FF_DEBUG
+#else
+#define MY_DEBUG_STR ""
+#define MY_FILEFLAGS_1 0x0L
+#endif
+#if NSSUTIL_BETA
+#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE
+#else
+#define MY_FILEFLAGS_2 MY_FILEFLAGS_1
+#endif
+
+#ifdef WINNT
+#define MY_FILEOS VOS_NT_WINDOWS32
+#else
+#define MY_FILEOS VOS__WINDOWS32
+#endif
+
+#define MY_INTERNAL_NAME MY_LIBNAME NSSUTIL_VMAJOR_STR
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version-information resource
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION NSSUTIL_VMAJOR,NSSUTIL_VMINOR,NSSUTIL_VPATCH,NSSUTIL_VBUILD
+ PRODUCTVERSION NSSUTIL_VMAJOR,NSSUTIL_VMINOR,NSSUTIL_VPATCH,NSSUTIL_VBUILD
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS MY_FILEFLAGS_2
+ FILEOS MY_FILEOS
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L // not used
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "CompanyName", "Mozilla Foundation\0"
+ VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0"
+ VALUE "FileVersion", NSSUTIL_VERSION "\0"
+ VALUE "InternalName", MY_INTERNAL_NAME "\0"
+ VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0"
+ VALUE "ProductName", "Network Security Services\0"
+ VALUE "ProductVersion", NSSUTIL_VERSION "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/lib/util/oidstring.c b/lib/util/oidstring.c
new file mode 100644
index 000000000..8bb963e08
--- /dev/null
+++ b/lib/util/oidstring.c
@@ -0,0 +1,114 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <string.h>
+#include "secitem.h"
+#include "secport.h"
+#include "secerr.h"
+
+/* if to->data is not NULL, and to->len is large enough to hold the result,
+ * then the resultant OID will be copyed into to->data, and to->len will be
+ * changed to show the actual OID length.
+ * Otherwise, memory for the OID will be allocated (from the caller's
+ * PLArenaPool, if pool is non-NULL) and to->data will receive the address
+ * of the allocated data, and to->len will receive the OID length.
+ * The original value of to->data is not freed when a new buffer is allocated.
+ *
+ * The input string may begin with "OID." and this still be ignored.
+ * The length of the input string is given in len. If len == 0, then
+ * len will be computed as strlen(from), meaning it must be NUL terminated.
+ * It is an error if from == NULL, or if *from == '\0'.
+ */
+
+SECStatus
+SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len)
+{
+ PRUint32 decimal_numbers = 0;
+ PRUint32 result_bytes = 0;
+ SECStatus rv;
+ PRUint8 result[1024];
+
+ static const PRUint32 max_decimal = (0xffffffff / 10);
+ static const char OIDstring[] = {"OID."};
+
+ if (!from || !to) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!len) {
+ len = PL_strlen(from);
+ }
+ if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
+ from += 4; /* skip leading "OID." if present */
+ len -= 4;
+ }
+ if (!len) {
+bad_data:
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ return SECFailure;
+ }
+ do {
+ PRUint32 decimal = 0;
+ while (len > 0 && isdigit(*from)) {
+ PRUint32 addend = (*from++ - '0');
+ --len;
+ if (decimal > max_decimal) /* overflow */
+ goto bad_data;
+ decimal = (decimal * 10) + addend;
+ if (decimal < addend) /* overflow */
+ goto bad_data;
+ }
+ if (len != 0 && *from != '.') {
+ goto bad_data;
+ }
+ if (decimal_numbers == 0) {
+ if (decimal > 2)
+ goto bad_data;
+ result[0] = decimal * 40;
+ result_bytes = 1;
+ } else if (decimal_numbers == 1) {
+ if (decimal > 40)
+ goto bad_data;
+ result[0] += decimal;
+ } else {
+ /* encode the decimal number, */
+ PRUint8 * rp;
+ PRUint32 num_bytes = 0;
+ PRUint32 tmp = decimal;
+ while (tmp) {
+ num_bytes++;
+ tmp >>= 7;
+ }
+ if (!num_bytes )
+ ++num_bytes; /* use one byte for a zero value */
+ if (num_bytes + result_bytes > sizeof result)
+ goto bad_data;
+ tmp = num_bytes;
+ rp = result + result_bytes - 1;
+ rp[tmp] = (PRUint8)(decimal & 0x7f);
+ decimal >>= 7;
+ while (--tmp > 0) {
+ rp[tmp] = (PRUint8)(decimal | 0x80);
+ decimal >>= 7;
+ }
+ result_bytes += num_bytes;
+ }
+ ++decimal_numbers;
+ if (len > 0) { /* skip trailing '.' */
+ ++from;
+ --len;
+ }
+ } while (len > 0);
+ /* now result contains result_bytes of data */
+ if (to->data && to->len >= result_bytes) {
+ PORT_Memcpy(to->data, result, to->len = result_bytes);
+ rv = SECSuccess;
+ } else {
+ SECItem result_item = {siBuffer, NULL, 0 };
+ result_item.data = result;
+ result_item.len = result_bytes;
+ rv = SECITEM_CopyItem(pool, to, &result_item);
+ }
+ return rv;
+}
diff --git a/lib/util/pkcs11.h b/lib/util/pkcs11.h
new file mode 100644
index 000000000..74ac250e0
--- /dev/null
+++ b/lib/util/pkcs11.h
@@ -0,0 +1,257 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security In.c Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ *
+ * The latest version of this header can be found at:
+ * http://www.rsalabs.com/pkcs/pkcs-11/index.html
+ */
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined. These
+ * macros are described below, and typical definitions for them
+ * are also given. Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a PKCS #11 library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for PKCS #11 structures should be set. The PKCS #11
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * In a Win32 environment, this might be done by using the
+ * following preprocessor directive before including pkcs11.h
+ * or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * In a UNIX environment, you're on your own here. You might
+ * not need to do anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object. It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * In a Win32 environment, it might be defined by
+ *
+ * #define CK_PTR *
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable PKCS #11 library function definition out of a
+ * return type and a function name. It should be used in the
+ * following fashion to define the exposed PKCS #11 functions in
+ * a PKCS #11 library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * )
+ * {
+ * ...
+ * }
+ *
+ * For defining a function in a Win32 PKCS #11 .dll, it might be
+ * defined by
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllexport) name
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable PKCS #11 library function declaration out of a
+ * return type and a function name. It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * );
+ *
+ * For declaring a function in a Win32 PKCS #11 .dll, it might
+ * be defined by
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllimport) name
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a PKCS #11 API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name. It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a PKCS #11 API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // PKCS #11 API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * For accessing functions in a Win32 PKCS #11 .dll, in might be
+ * defined by
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __declspec(dllimport) (* name)
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV. It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * In a Win32 environment, it might be defined by
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ * In a UNIX environment, it might be defined by
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various PKCS #11 types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y) x##y
+
+
+/* packing defines */
+#include "pkcs11p.h"
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the PKCS #11
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points. That is, for
+ * each PKCS #11 function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the PKCS #11
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points. A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's PKCS #11 version
+ * and then a whole slew of function pointers to the routines in
+ * the library. This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+ CK_VERSION version; /* PKCS #11 version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the PKCS #11
+ * function prototypes. */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+/* unpack */
+#include "pkcs11u.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/util/pkcs11f.h b/lib/util/pkcs11f.h
new file mode 100644
index 000000000..732b1a159
--- /dev/null
+++ b/lib/util/pkcs11f.h
@@ -0,0 +1,905 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security In.c Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ */
+/* This function contains pretty much everything about all the */
+/* PKCS #11 function prototypes. Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+
+
+/* General-purpose */
+
+/* C_Initialize initializes the PKCS #11 library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
+ * cast to CK_C_INITIALIZE_ARGS_PTR
+ * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * PKCS #11 library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about PKCS #11. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_INFO_PTR pInfo /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
+ * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_BBOOL tokenPresent, /* only slots with tokens? */
+ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
+ CK_ULONG_PTR pulCount /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the ID of the slot */
+ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of token's slot */
+ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
+ CK_ULONG_PTR pulCount /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_MECHANISM_TYPE type, /* type of mechanism */
+ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
+ CK_ULONG ulPinLen, /* length in bytes of the PIN */
+ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
+ CK_ULONG ulPinLen /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
+ CK_ULONG ulOldLen, /* length of the old PIN */
+ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
+ CK_ULONG ulNewLen /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the slot's ID */
+ CK_FLAGS flags, /* from CK_SESSION_INFO */
+ CK_VOID_PTR pApplication, /* passed to callback */
+ CK_NOTIFY Notify, /* callback function */
+ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_SESSION_INFO_PTR pInfo /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* gets state */
+ CK_ULONG_PTR pulOperationStateLen /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* holds state */
+ CK_ULONG ulOperationStateLen, /* holds state length */
+ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
+ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_USER_TYPE userType, /* the user type */
+ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
+ CK_ULONG ulPinLen /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ULONG_PTR pulSize /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
+ CK_ULONG ulCount /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
+ CK_ULONG ulMaxObjectCount, /* max handles to get */
+ CK_ULONG_PTR pulObjectCount /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pData, /* the plaintext data */
+ CK_ULONG ulDataLen, /* bytes of plaintext */
+ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext data len */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
+ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedData, /* ciphertext */
+ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
+ CK_BYTE_PTR pData, /* gets plaintext */
+ CK_ULONG_PTR pulDataLen /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
+ CK_ULONG ulEncryptedPartLen, /* input length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pLastPart, /* gets plaintext */
+ CK_ULONG_PTR pulLastPartLen /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* data to be digested */
+ CK_ULONG ulDataLen, /* bytes of data to digest */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* data to be digested */
+ CK_ULONG ulPartLen /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hKey /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* the data to sign */
+ CK_ULONG ulPartLen /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* signed data */
+ CK_ULONG ulDataLen, /* length of signed data */
+ CK_BYTE_PTR pSignature, /* signature */
+ CK_ULONG ulSignatureLen /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* signed data */
+ CK_ULONG ulPartLen /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen, /* signature length */
+ CK_BYTE_PTR pData, /* gets signed data */
+ CK_ULONG_PTR pulDataLen /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
+ CK_ULONG ulCount, /* # of attrs in template */
+ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session
+ * handle */
+ CK_MECHANISM_PTR pMechanism, /* key-gen
+ * mech. */
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template
+ * for pub.
+ * key */
+ CK_ULONG ulPublicKeyAttributeCount, /* # pub.
+ * attrs. */
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template
+ * for priv.
+ * key */
+ CK_ULONG ulPrivateKeyAttributeCount, /* # priv.
+ * attrs. */
+ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub.
+ * key
+ * handle */
+ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets
+ * priv. key
+ * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
+ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
+ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
+ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
+ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
+ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
+ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
+ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
+ CK_OBJECT_HANDLE hBaseKey, /* base key */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSeed, /* the seed material */
+ CK_ULONG ulSeedLen /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR RandomData, /* receives the random data */
+ CK_ULONG ulRandomLen /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for PKCS #11 Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FLAGS flags, /* blocking/nonblocking flag */
+ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
+ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
+);
+#endif
diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h
new file mode 100644
index 000000000..2e88eb4fc
--- /dev/null
+++ b/lib/util/pkcs11n.h
@@ -0,0 +1,464 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _PKCS11N_H_
+#define _PKCS11N_H_
+
+#ifdef DEBUG
+static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$";
+#endif /* DEBUG */
+
+/*
+ * pkcs11n.h
+ *
+ * This file contains the NSS-specific type definitions for Cryptoki
+ * (PKCS#11).
+ */
+
+/*
+ * NSSCK_VENDOR_NSS
+ *
+ * Cryptoki reserves the high half of all the number spaces for
+ * vendor-defined use. I'd like to keep all of our NSS-
+ * specific values together, but not in the oh-so-obvious
+ * 0x80000001, 0x80000002, etc. area. So I've picked an offset,
+ * and constructed values for the beginnings of our spaces.
+ *
+ * Note that some "historical" Netscape values don't fall within
+ * this range.
+ */
+#define NSSCK_VENDOR_NSS 0x4E534350 /* NSCP */
+
+/*
+ * NSS-defined object classes
+ *
+ */
+#define CKO_NSS (CKO_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKO_NSS_CRL (CKO_NSS + 1)
+#define CKO_NSS_SMIME (CKO_NSS + 2)
+#define CKO_NSS_TRUST (CKO_NSS + 3)
+#define CKO_NSS_BUILTIN_ROOT_LIST (CKO_NSS + 4)
+#define CKO_NSS_NEWSLOT (CKO_NSS + 5)
+#define CKO_NSS_DELSLOT (CKO_NSS + 6)
+
+
+/*
+ * NSS-defined key types
+ *
+ */
+#define CKK_NSS (CKK_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKK_NSS_PKCS8 (CKK_NSS + 1)
+
+#define CKK_NSS_JPAKE_ROUND1 (CKK_NSS + 2)
+#define CKK_NSS_JPAKE_ROUND2 (CKK_NSS + 3)
+
+/*
+ * NSS-defined certificate types
+ *
+ */
+#define CKC_NSS (CKC_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+/* FAKE PKCS #11 defines */
+#define CKA_DIGEST 0x81000000L
+#define CKA_FLAGS_ONLY 0 /* CKA_CLASS */
+
+/*
+ * NSS-defined object attributes
+ *
+ */
+#define CKA_NSS (CKA_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKA_NSS_URL (CKA_NSS + 1)
+#define CKA_NSS_EMAIL (CKA_NSS + 2)
+#define CKA_NSS_SMIME_INFO (CKA_NSS + 3)
+#define CKA_NSS_SMIME_TIMESTAMP (CKA_NSS + 4)
+#define CKA_NSS_PKCS8_SALT (CKA_NSS + 5)
+#define CKA_NSS_PASSWORD_CHECK (CKA_NSS + 6)
+#define CKA_NSS_EXPIRES (CKA_NSS + 7)
+#define CKA_NSS_KRL (CKA_NSS + 8)
+
+#define CKA_NSS_PQG_COUNTER (CKA_NSS + 20)
+#define CKA_NSS_PQG_SEED (CKA_NSS + 21)
+#define CKA_NSS_PQG_H (CKA_NSS + 22)
+#define CKA_NSS_PQG_SEED_BITS (CKA_NSS + 23)
+#define CKA_NSS_MODULE_SPEC (CKA_NSS + 24)
+#define CKA_NSS_OVERRIDE_EXTENSIONS (CKA_NSS + 25)
+
+#define CKA_NSS_JPAKE_SIGNERID (CKA_NSS + 26)
+#define CKA_NSS_JPAKE_PEERID (CKA_NSS + 27)
+#define CKA_NSS_JPAKE_GX1 (CKA_NSS + 28)
+#define CKA_NSS_JPAKE_GX2 (CKA_NSS + 29)
+#define CKA_NSS_JPAKE_GX3 (CKA_NSS + 30)
+#define CKA_NSS_JPAKE_GX4 (CKA_NSS + 31)
+#define CKA_NSS_JPAKE_X2 (CKA_NSS + 32)
+#define CKA_NSS_JPAKE_X2S (CKA_NSS + 33)
+
+/*
+ * Trust attributes:
+ *
+ * If trust goes standard, these probably will too. So I'll
+ * put them all in one place.
+ */
+
+#define CKA_TRUST (CKA_NSS + 0x2000)
+
+/* "Usage" key information */
+#define CKA_TRUST_DIGITAL_SIGNATURE (CKA_TRUST + 1)
+#define CKA_TRUST_NON_REPUDIATION (CKA_TRUST + 2)
+#define CKA_TRUST_KEY_ENCIPHERMENT (CKA_TRUST + 3)
+#define CKA_TRUST_DATA_ENCIPHERMENT (CKA_TRUST + 4)
+#define CKA_TRUST_KEY_AGREEMENT (CKA_TRUST + 5)
+#define CKA_TRUST_KEY_CERT_SIGN (CKA_TRUST + 6)
+#define CKA_TRUST_CRL_SIGN (CKA_TRUST + 7)
+
+/* "Purpose" trust information */
+#define CKA_TRUST_SERVER_AUTH (CKA_TRUST + 8)
+#define CKA_TRUST_CLIENT_AUTH (CKA_TRUST + 9)
+#define CKA_TRUST_CODE_SIGNING (CKA_TRUST + 10)
+#define CKA_TRUST_EMAIL_PROTECTION (CKA_TRUST + 11)
+#define CKA_TRUST_IPSEC_END_SYSTEM (CKA_TRUST + 12)
+#define CKA_TRUST_IPSEC_TUNNEL (CKA_TRUST + 13)
+#define CKA_TRUST_IPSEC_USER (CKA_TRUST + 14)
+#define CKA_TRUST_TIME_STAMPING (CKA_TRUST + 15)
+#define CKA_TRUST_STEP_UP_APPROVED (CKA_TRUST + 16)
+
+#define CKA_CERT_SHA1_HASH (CKA_TRUST + 100)
+#define CKA_CERT_MD5_HASH (CKA_TRUST + 101)
+
+/* NSS trust stuff */
+
+/* HISTORICAL: define used to pass in the database key for DSA private keys */
+#define CKA_NETSCAPE_DB 0xD5A0DB00L
+#define CKA_NETSCAPE_TRUST 0x80000001L
+
+/* FAKE PKCS #11 defines */
+#define CKM_FAKE_RANDOM 0x80000efeUL
+#define CKM_INVALID_MECHANISM 0xffffffffUL
+
+/*
+ * NSS-defined crypto mechanisms
+ *
+ */
+#define CKM_NSS (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKM_NSS_AES_KEY_WRAP (CKM_NSS + 1)
+#define CKM_NSS_AES_KEY_WRAP_PAD (CKM_NSS + 2)
+
+/* HKDF key derivation mechanisms. See CK_NSS_HKDFParams for documentation. */
+#define CKM_NSS_HKDF_SHA1 (CKM_NSS + 3)
+#define CKM_NSS_HKDF_SHA256 (CKM_NSS + 4)
+#define CKM_NSS_HKDF_SHA384 (CKM_NSS + 5)
+#define CKM_NSS_HKDF_SHA512 (CKM_NSS + 6)
+
+/* J-PAKE round 1 key generation mechanisms.
+ *
+ * Required template attributes: CKA_PRIME, CKA_SUBPRIME, CKA_BASE,
+ * CKA_NSS_JPAKE_SIGNERID
+ * Output key type: CKK_NSS_JPAKE_ROUND1
+ * Output key class: CKO_PRIVATE_KEY
+ * Parameter type: CK_NSS_JPAKERound1Params
+ *
+ */
+#define CKM_NSS_JPAKE_ROUND1_SHA1 (CKM_NSS + 7)
+#define CKM_NSS_JPAKE_ROUND1_SHA256 (CKM_NSS + 8)
+#define CKM_NSS_JPAKE_ROUND1_SHA384 (CKM_NSS + 9)
+#define CKM_NSS_JPAKE_ROUND1_SHA512 (CKM_NSS + 10)
+
+/* J-PAKE round 2 key derivation mechanisms.
+ *
+ * Required template attributes: CKA_NSS_JPAKE_PEERID
+ * Input key type: CKK_NSS_JPAKE_ROUND1
+ * Output key type: CKK_NSS_JPAKE_ROUND2
+ * Output key class: CKO_PRIVATE_KEY
+ * Parameter type: CK_NSS_JPAKERound2Params
+ */
+#define CKM_NSS_JPAKE_ROUND2_SHA1 (CKM_NSS + 11)
+#define CKM_NSS_JPAKE_ROUND2_SHA256 (CKM_NSS + 12)
+#define CKM_NSS_JPAKE_ROUND2_SHA384 (CKM_NSS + 13)
+#define CKM_NSS_JPAKE_ROUND2_SHA512 (CKM_NSS + 14)
+
+/* J-PAKE final key material derivation mechanisms
+ *
+ * Input key type: CKK_NSS_JPAKE_ROUND2
+ * Output key type: CKK_GENERIC_SECRET
+ * Output key class: CKO_SECRET_KEY
+ * Parameter type: CK_NSS_JPAKEFinalParams
+ *
+ * You must apply a KDF (e.g. CKM_NSS_HKDF_*) to resultant keying material
+ * to get a key with uniformly distributed bits.
+ */
+#define CKM_NSS_JPAKE_FINAL_SHA1 (CKM_NSS + 15)
+#define CKM_NSS_JPAKE_FINAL_SHA256 (CKM_NSS + 16)
+#define CKM_NSS_JPAKE_FINAL_SHA384 (CKM_NSS + 17)
+#define CKM_NSS_JPAKE_FINAL_SHA512 (CKM_NSS + 18)
+
+/* Constant-time MAC mechanisms:
+ *
+ * These operations verify a padded, MAC-then-encrypt block of data in
+ * constant-time. Because of the order of operations, the padding bytes are not
+ * protected by the MAC. However, disclosing the value of the padding bytes
+ * gives an attacker the ability to decrypt ciphertexts. Such disclosure can be
+ * as subtle as taking slightly less time to perform the MAC when the padding
+ * is one byte longer. See https://www.isg.rhul.ac.uk/tls/
+ *
+ * CKM_NSS_HMAC_CONSTANT_TIME: performs an HMAC authentication.
+ * CKM_NSS_SSL3_MAC_CONSTANT_TIME: performs an authentication with SSLv3 MAC.
+ *
+ * Parameter type: CK_NSS_MAC_CONSTANT_TIME_PARAMS
+ */
+#define CKM_NSS_HMAC_CONSTANT_TIME (CKM_NSS + 19)
+#define CKM_NSS_SSL3_MAC_CONSTANT_TIME (CKM_NSS + 20)
+
+/*
+ * HISTORICAL:
+ * Do not attempt to use these. They are only used by NETSCAPE's internal
+ * PKCS #11 interface. Most of these are place holders for other mechanism
+ * and will change in the future.
+ */
+#define CKM_NETSCAPE_PBE_SHA1_DES_CBC 0x80000002UL
+#define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC 0x80000003UL
+#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC 0x80000004UL
+#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC 0x80000005UL
+#define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4 0x80000006UL
+#define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4 0x80000007UL
+#define CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC 0x80000008UL
+#define CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN 0x80000009UL
+#define CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN 0x8000000aUL
+#define CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN 0x8000000bUL
+
+#define CKM_TLS_PRF_GENERAL 0x80000373UL
+
+typedef struct CK_NSS_JPAKEPublicValue {
+ CK_BYTE * pGX;
+ CK_ULONG ulGXLen;
+ CK_BYTE * pGV;
+ CK_ULONG ulGVLen;
+ CK_BYTE * pR;
+ CK_ULONG ulRLen;
+} CK_NSS_JPAKEPublicValue;
+
+typedef struct CK_NSS_JPAKERound1Params {
+ CK_NSS_JPAKEPublicValue gx1; /* out */
+ CK_NSS_JPAKEPublicValue gx2; /* out */
+} CK_NSS_JPAKERound1Params;
+
+typedef struct CK_NSS_JPAKERound2Params {
+ CK_BYTE * pSharedKey; /* in */
+ CK_ULONG ulSharedKeyLen; /* in */
+ CK_NSS_JPAKEPublicValue gx3; /* in */
+ CK_NSS_JPAKEPublicValue gx4; /* in */
+ CK_NSS_JPAKEPublicValue A; /* out */
+} CK_NSS_JPAKERound2Params;
+
+typedef struct CK_NSS_JPAKEFinalParams {
+ CK_NSS_JPAKEPublicValue B; /* in */
+} CK_NSS_JPAKEFinalParams;
+
+/* macAlg: the MAC algorithm to use. This determines the hash function used in
+ * the HMAC/SSLv3 MAC calculations.
+ * ulBodyTotalLen: the total length of the data, including padding bytes and
+ * padding length.
+ * pHeader: points to a block of data that contains additional data to
+ * authenticate. For TLS this includes the sequence number etc. For SSLv3,
+ * this also includes the initial padding bytes.
+ *
+ * NOTE: the softoken's implementation of CKM_NSS_HMAC_CONSTANT_TIME and
+ * CKM_NSS_SSL3_MAC_CONSTANT_TIME requires that the sum of ulBodyTotalLen
+ * and ulHeaderLen be much smaller than 2^32 / 8 bytes because it uses an
+ * unsigned int variable to represent the length in bits. This should not
+ * be a problem because the SSL/TLS protocol limits the size of an SSL
+ * record to something considerably less than 2^32 bytes.
+ */
+typedef struct CK_NSS_MAC_CONSTANT_TIME_PARAMS {
+ CK_MECHANISM_TYPE macAlg; /* in */
+ CK_ULONG ulBodyTotalLen; /* in */
+ CK_BYTE * pHeader; /* in */
+ CK_ULONG ulHeaderLen; /* in */
+} CK_NSS_MAC_CONSTANT_TIME_PARAMS;
+
+/*
+ * NSS-defined return values
+ *
+ */
+#define CKR_NSS (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+#define CKR_NSS_CERTDB_FAILED (CKR_NSS + 1)
+#define CKR_NSS_KEYDB_FAILED (CKR_NSS + 2)
+
+/* Mandatory parameter for the CKM_NSS_HKDF_* key deriviation mechanisms.
+ See RFC 5869.
+
+ bExtract: If set, HKDF-Extract will be applied to the input key. If
+ the optional salt is given, it is used; otherwise, the salt is
+ set to a sequence of zeros equal in length to the HMAC output.
+ If bExpand is not set, then the key template given to
+ C_DeriveKey must indicate an output key size less than or equal
+ to the output size of the HMAC.
+
+ bExpand: If set, HKDF-Expand will be applied to the input key (if
+ bExtract is not set) or to the result of HKDF-Extract (if
+ bExtract is set). Any info given in the optional pInfo field will
+ be included in the calculation.
+
+ The size of the output key must be specified in the template passed to
+ C_DeriveKey.
+*/
+typedef struct CK_NSS_HKDFParams {
+ CK_BBOOL bExtract;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_BBOOL bExpand;
+ CK_BYTE_PTR pInfo;
+ CK_ULONG ulInfoLen;
+} CK_NSS_HKDFParams;
+
+/*
+ * Trust info
+ *
+ * This isn't part of the Cryptoki standard (yet), so I'm putting
+ * all the definitions here. Some of this would move to nssckt.h
+ * if trust info were made part of the standard. In view of this
+ * possibility, I'm putting my (NSS) values in the NSS
+ * vendor space, like everything else.
+ */
+
+typedef CK_ULONG CK_TRUST;
+
+/* The following trust types are defined: */
+#define CKT_VENDOR_DEFINED 0x80000000
+
+#define CKT_NSS (CKT_VENDOR_DEFINED|NSSCK_VENDOR_NSS)
+
+/* If trust goes standard, these'll probably drop out of vendor space. */
+#define CKT_NSS_TRUSTED (CKT_NSS + 1)
+#define CKT_NSS_TRUSTED_DELEGATOR (CKT_NSS + 2)
+#define CKT_NSS_MUST_VERIFY_TRUST (CKT_NSS + 3)
+#define CKT_NSS_NOT_TRUSTED (CKT_NSS + 10)
+#define CKT_NSS_TRUST_UNKNOWN (CKT_NSS + 5) /* default */
+
+/*
+ * These may well remain NSS-specific; I'm only using them
+ * to cache resolution data.
+ */
+#define CKT_NSS_VALID_DELEGATOR (CKT_NSS + 11)
+
+
+/*
+ * old definitions. They still exist, but the plain meaning of the
+ * labels have never been accurate to what was really implemented.
+ * The new labels correctly reflect what the values effectively mean.
+ */
+#if defined(__GNUC__) && (__GNUC__ > 3)
+/* make GCC warn when we use these #defines */
+/*
+ * This is really painful because GCC doesn't allow us to mark random
+ * #defines as deprecated. We can only mark the following:
+ * functions, variables, and types.
+ * const variables will create extra storage for everyone including this
+ * header file, so it's undesirable.
+ * functions could be inlined to prevent storage creation, but will fail
+ * when constant values are expected (like switch statements).
+ * enum types do not seem to pay attention to the deprecated attribute.
+ *
+ * That leaves typedefs. We declare new types that we then deprecate, then
+ * cast the resulting value to the deprecated type in the #define, thus
+ * producting the warning when the #define is used.
+ */
+#if (__GNUC__ == 4) && (__GNUC_MINOR__ < 5)
+/* The mac doesn't like the friendlier deprecate messages. I'm assuming this
+ * is a gcc version issue rather than mac or ppc specific */
+typedef CK_TRUST __CKT_NSS_UNTRUSTED __attribute__((deprecated));
+typedef CK_TRUST __CKT_NSS_VALID __attribute__ ((deprecated));
+typedef CK_TRUST __CKT_NSS_MUST_VERIFY __attribute__((deprecated));
+#else
+/* when possible, get a full deprecation warning. This works on gcc 4.5
+ * it may work on earlier versions of gcc */
+typedef CK_TRUST __CKT_NSS_UNTRUSTED __attribute__((deprecated
+ ("CKT_NSS_UNTRUSTED really means CKT_NSS_MUST_VERIFY_TRUST")));
+typedef CK_TRUST __CKT_NSS_VALID __attribute__ ((deprecated
+ ("CKT_NSS_VALID really means CKT_NSS_NOT_TRUSTED")));
+typedef CK_TRUST __CKT_NSS_MUST_VERIFY __attribute__((deprecated
+ ("CKT_NSS_MUST_VERIFY really functions as CKT_NSS_TRUST_UNKNOWN")));
+#endif
+#define CKT_NSS_UNTRUSTED ((__CKT_NSS_UNTRUSTED)CKT_NSS_MUST_VERIFY_TRUST)
+#define CKT_NSS_VALID ((__CKT_NSS_VALID) CKT_NSS_NOT_TRUSTED)
+/* keep the old value for compatibility reasons*/
+#define CKT_NSS_MUST_VERIFY ((__CKT_NSS_MUST_VERIFY)(CKT_NSS +4))
+#else
+#ifdef _WIN32
+/* This magic gets the windows compiler to give us a deprecation
+ * warning */
+#pragma deprecated(CKT_NSS_UNTRUSTED, CKT_NSS_MUST_VERIFY, CKT_NSS_VALID)
+#endif
+/* CKT_NSS_UNTRUSTED really means CKT_NSS_MUST_VERIFY_TRUST */
+#define CKT_NSS_UNTRUSTED CKT_NSS_MUST_VERIFY_TRUST
+/* CKT_NSS_VALID really means CKT_NSS_NOT_TRUSTED */
+#define CKT_NSS_VALID CKT_NSS_NOT_TRUSTED
+/* CKT_NSS_MUST_VERIFY was always treated as CKT_NSS_TRUST_UNKNOWN */
+#define CKT_NSS_MUST_VERIFY (CKT_NSS + 4) /*really means trust unknown*/
+#endif
+
+/* don't leave old programs in a lurch just yet, give them the old NETSCAPE
+ * synonym */
+#define CKO_NETSCAPE_CRL CKO_NSS_CRL
+#define CKO_NETSCAPE_SMIME CKO_NSS_SMIME
+#define CKO_NETSCAPE_TRUST CKO_NSS_TRUST
+#define CKO_NETSCAPE_BUILTIN_ROOT_LIST CKO_NSS_BUILTIN_ROOT_LIST
+#define CKO_NETSCAPE_NEWSLOT CKO_NSS_NEWSLOT
+#define CKO_NETSCAPE_DELSLOT CKO_NSS_DELSLOT
+#define CKK_NETSCAPE_PKCS8 CKK_NSS_PKCS8
+#define CKA_NETSCAPE_URL CKA_NSS_URL
+#define CKA_NETSCAPE_EMAIL CKA_NSS_EMAIL
+#define CKA_NETSCAPE_SMIME_INFO CKA_NSS_SMIME_INFO
+#define CKA_NETSCAPE_SMIME_TIMESTAMP CKA_NSS_SMIME_TIMESTAMP
+#define CKA_NETSCAPE_PKCS8_SALT CKA_NSS_PKCS8_SALT
+#define CKA_NETSCAPE_PASSWORD_CHECK CKA_NSS_PASSWORD_CHECK
+#define CKA_NETSCAPE_EXPIRES CKA_NSS_EXPIRES
+#define CKA_NETSCAPE_KRL CKA_NSS_KRL
+#define CKA_NETSCAPE_PQG_COUNTER CKA_NSS_PQG_COUNTER
+#define CKA_NETSCAPE_PQG_SEED CKA_NSS_PQG_SEED
+#define CKA_NETSCAPE_PQG_H CKA_NSS_PQG_H
+#define CKA_NETSCAPE_PQG_SEED_BITS CKA_NSS_PQG_SEED_BITS
+#define CKA_NETSCAPE_MODULE_SPEC CKA_NSS_MODULE_SPEC
+#define CKM_NETSCAPE_AES_KEY_WRAP CKM_NSS_AES_KEY_WRAP
+#define CKM_NETSCAPE_AES_KEY_WRAP_PAD CKM_NSS_AES_KEY_WRAP_PAD
+#define CKR_NETSCAPE_CERTDB_FAILED CKR_NSS_CERTDB_FAILED
+#define CKR_NETSCAPE_KEYDB_FAILED CKR_NSS_KEYDB_FAILED
+
+#define CKT_NETSCAPE_TRUSTED CKT_NSS_TRUSTED
+#define CKT_NETSCAPE_TRUSTED_DELEGATOR CKT_NSS_TRUSTED_DELEGATOR
+#define CKT_NETSCAPE_UNTRUSTED CKT_NSS_UNTRUSTED
+#define CKT_NETSCAPE_MUST_VERIFY CKT_NSS_MUST_VERIFY
+#define CKT_NETSCAPE_TRUST_UNKNOWN CKT_NSS_TRUST_UNKNOWN
+#define CKT_NETSCAPE_VALID CKT_NSS_VALID
+#define CKT_NETSCAPE_VALID_DELEGATOR CKT_NSS_VALID_DELEGATOR
+
+/*
+ * These are not really PKCS #11 values specifically. They are the 'loadable'
+ * module spec NSS uses. The are available for others to use as well, but not
+ * part of the formal PKCS #11 spec.
+ *
+ * The function 'FIND' returns an array of PKCS #11 initialization strings
+ * The function 'ADD' takes a PKCS #11 initialization string and stores it.
+ * The function 'DEL' takes a 'name= library=' value and deletes the associated
+ * string.
+ * The function 'RELEASE' frees the array returned by 'FIND'
+ */
+#define SECMOD_MODULE_DB_FUNCTION_FIND 0
+#define SECMOD_MODULE_DB_FUNCTION_ADD 1
+#define SECMOD_MODULE_DB_FUNCTION_DEL 2
+#define SECMOD_MODULE_DB_FUNCTION_RELEASE 3
+typedef char ** (PR_CALLBACK *SECMODModuleDBFunc)(unsigned long function,
+ char *parameters, void *moduleSpec);
+
+/* softoken slot ID's */
+#define SFTK_MIN_USER_SLOT_ID 4
+#define SFTK_MAX_USER_SLOT_ID 100
+#define SFTK_MIN_FIPS_USER_SLOT_ID 101
+#define SFTK_MAX_FIPS_USER_SLOT_ID 127
+
+
+#endif /* _PKCS11N_H_ */
diff --git a/lib/util/pkcs11p.h b/lib/util/pkcs11p.h
new file mode 100644
index 000000000..744c82034
--- /dev/null
+++ b/lib/util/pkcs11p.h
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security Inc. Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ */
+/* these data types are platform/implementation dependent. */
+/*
+ * Packing was removed from the shipped RSA header files, even
+ * though it's still needed. put in a central file to help merging..
+ */
+
+#if defined(_WIN32)
+#ifdef _MSC_VER
+#pragma warning(disable:4103)
+#endif
+#pragma pack(push, cryptoki, 1)
+#endif
+
diff --git a/lib/util/pkcs11t.h b/lib/util/pkcs11t.h
new file mode 100644
index 000000000..b00346162
--- /dev/null
+++ b/lib/util/pkcs11t.h
@@ -0,0 +1,1793 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#include "prtypes.h"
+
+#define CK_PTR *
+#define CK_NULL_PTR 0
+#define CK_CALLBACK_FUNCTION(rtype,func) rtype (PR_CALLBACK * func)
+#define CK_DECLARE_FUNCTION(rtype,func) extern rtype func
+#define CK_DECLARE_FUNCTION_POINTER(rtype,func) rtype (PR_CALLBACK * func)
+
+#define CK_INVALID_SESSION 0
+
+/* an unsigned 8-bit value */
+typedef unsigned char CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+/* CK_LONG is new for v2.0 */
+typedef long int CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE 0
+
+
+typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+typedef CK_CHAR CK_PTR CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
+typedef CK_ULONG CK_PTR CK_ULONG_PTR;
+typedef void CK_PTR CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+/* pack */
+#include "pkcs11p.h"
+
+typedef struct CK_VERSION {
+ CK_BYTE major; /* integer portion of version number */
+ CK_BYTE minor; /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+ /* manufacturerID and libraryDecription have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_VERSION cryptokiVersion; /* PKCS #11 interface ver */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags; /* must be zero */
+
+ /* libraryDescription and libraryVersion are new for v2.0 */
+ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
+ CK_VERSION libraryVersion; /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * PKCS #11 provides to an application */
+/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER 0
+
+
+typedef CK_ULONG CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+ /* slotDescription and manufacturerID have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR slotDescription[64]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags;
+
+ /* hardwareVersion and firmwareVersion are new for v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */
+#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/
+#define CKF_HW_SLOT 0x00000004 /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+ /* label, manufacturerID, and model have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR label[32]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_UTF8CHAR model[16]; /* blank padded */
+ CK_CHAR serialNumber[16]; /* blank padded */
+ CK_FLAGS flags; /* see below */
+
+ /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
+ * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
+ * changed from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulMaxSessionCount; /* max open sessions */
+ CK_ULONG ulSessionCount; /* sess. now open */
+ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
+ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
+ CK_ULONG ulMaxPinLen; /* in bytes */
+ CK_ULONG ulMinPinLen; /* in bytes */
+ CK_ULONG ulTotalPublicMemory; /* in bytes */
+ CK_ULONG ulFreePublicMemory; /* in bytes */
+ CK_ULONG ulTotalPrivateMemory; /* in bytes */
+ CK_ULONG ulFreePrivateMemory; /* in bytes */
+
+ /* hardwareVersion, firmwareVersion, and time are new for
+ * v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+ CK_CHAR utcTime[16]; /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RNG 0x00000001 /* has random #
+ * generator */
+#define CKF_WRITE_PROTECTED 0x00000002 /* token is
+ * write-
+ * protected */
+#define CKF_LOGIN_REQUIRED 0x00000004 /* user must
+ * login */
+#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's
+ * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020
+
+/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means
+ * that the token has some sort of clock. The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN 0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the PKCS #11 library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200
+
+/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED 0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is
+ * true, the token supports secondary authentication for
+ * private key objects. This flag is deprecated in v2.11 and
+ onwards. */
+#define CKF_SECONDARY_AUTHENTICATION 0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW 0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY 0x00020000
+
+/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible. */
+#define CKF_USER_PIN_LOCKED 0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW 0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY 0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED 0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a PKCS #11-assigned value that
+ * identifies a session */
+typedef CK_ULONG CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of PKCS #11 users */
+/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO 0
+/* Normal user */
+#define CKU_USER 1
+/* Context specific (added in v2.20) */
+#define CKU_CONTEXT_SPECIFIC 2
+
+/* CK_STATE enumerates the session states */
+/* CK_STATE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_STATE;
+#define CKS_RO_PUBLIC_SESSION 0
+#define CKS_RO_USER_FUNCTIONS 1
+#define CKS_RW_PUBLIC_SESSION 2
+#define CKS_RW_USER_FUNCTIONS 3
+#define CKS_RW_SO_FUNCTIONS 4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+ CK_SLOT_ID slotID;
+ CK_STATE state;
+ CK_FLAGS flags; /* see below */
+
+ /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulDeviceError; /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RW_SESSION 0x00000002 /* session is r/w */
+#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object */
+typedef CK_ULONG CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that PKCS #11 recognizes. It is defined
+ * as follows: */
+/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+/* CKO_HW_FEATURE is new for v2.10 */
+/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
+/* CKO_MECHANISM is new for v2.20 */
+#define CKO_DATA 0x00000000
+#define CKO_CERTIFICATE 0x00000001
+#define CKO_PUBLIC_KEY 0x00000002
+#define CKO_PRIVATE_KEY 0x00000003
+#define CKO_SECRET_KEY 0x00000004
+#define CKO_HW_FEATURE 0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_MECHANISM 0x00000007
+#define CKO_VENDOR_DEFINED 0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+/* CKH_USER_INTERFACE is new for v2.20 */
+#define CKH_MONOTONIC_COUNTER 0x00000001
+#define CKH_CLOCK 0x00000002
+#define CKH_USER_INTERFACE 0x00000003
+#define CKH_VENDOR_DEFINED 0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA 0x00000000
+#define CKK_DSA 0x00000001
+#define CKK_DH 0x00000002
+
+/* CKK_ECDSA and CKK_KEA are new for v2.0 */
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA 0x00000003
+#define CKK_EC 0x00000003
+#define CKK_X9_42_DH 0x00000004
+#define CKK_KEA 0x00000005
+
+#define CKK_GENERIC_SECRET 0x00000010
+#define CKK_RC2 0x00000011
+#define CKK_RC4 0x00000012
+#define CKK_DES 0x00000013
+#define CKK_DES2 0x00000014
+#define CKK_DES3 0x00000015
+
+/* all these key types are new for v2.0 */
+#define CKK_CAST 0x00000016
+#define CKK_CAST3 0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5 0x00000018
+#define CKK_CAST128 0x00000018
+#define CKK_RC5 0x00000019
+#define CKK_IDEA 0x0000001A
+#define CKK_SKIPJACK 0x0000001B
+#define CKK_BATON 0x0000001C
+#define CKK_JUNIPER 0x0000001D
+#define CKK_CDMF 0x0000001E
+#define CKK_AES 0x0000001F
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKK_BLOWFISH 0x00000020
+#define CKK_TWOFISH 0x00000021
+
+/* Camellia is proposed for v2.20 Amendment 3 */
+#define CKK_CAMELLIA 0x00000025
+
+#define CKK_SEED 0x00000026
+
+#define CKK_VENDOR_DEFINED 0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+/* CKC_X_509_ATTR_CERT is new for v2.10 */
+/* CKC_WTLS is new for v2.20 */
+#define CKC_X_509 0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_WTLS 0x00000002
+#define CKC_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+ consists of an array of values. */
+#define CKF_ARRAY_ATTRIBUTE 0x40000000
+
+/* The following attribute types are defined: */
+#define CKA_CLASS 0x00000000
+#define CKA_TOKEN 0x00000001
+#define CKA_PRIVATE 0x00000002
+#define CKA_LABEL 0x00000003
+#define CKA_APPLICATION 0x00000010
+#define CKA_VALUE 0x00000011
+
+/* CKA_OBJECT_ID is new for v2.10 */
+#define CKA_OBJECT_ID 0x00000012
+
+#define CKA_CERTIFICATE_TYPE 0x00000080
+#define CKA_ISSUER 0x00000081
+#define CKA_SERIAL_NUMBER 0x00000082
+
+/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new
+ * for v2.10 */
+#define CKA_AC_ISSUER 0x00000083
+#define CKA_OWNER 0x00000084
+#define CKA_ATTR_TYPES 0x00000085
+
+/* CKA_TRUSTED is new for v2.11 */
+#define CKA_TRUSTED 0x00000086
+
+/* CKA_CERTIFICATE_CATEGORY ...
+ * CKA_CHECK_VALUE are new for v2.20 */
+#define CKA_CERTIFICATE_CATEGORY 0x00000087
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088
+#define CKA_URL 0x00000089
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B
+#define CKA_CHECK_VALUE 0x00000090
+
+#define CKA_KEY_TYPE 0x00000100
+#define CKA_SUBJECT 0x00000101
+#define CKA_ID 0x00000102
+#define CKA_SENSITIVE 0x00000103
+#define CKA_ENCRYPT 0x00000104
+#define CKA_DECRYPT 0x00000105
+#define CKA_WRAP 0x00000106
+#define CKA_UNWRAP 0x00000107
+#define CKA_SIGN 0x00000108
+#define CKA_SIGN_RECOVER 0x00000109
+#define CKA_VERIFY 0x0000010A
+#define CKA_VERIFY_RECOVER 0x0000010B
+#define CKA_DERIVE 0x0000010C
+#define CKA_START_DATE 0x00000110
+#define CKA_END_DATE 0x00000111
+#define CKA_MODULUS 0x00000120
+#define CKA_MODULUS_BITS 0x00000121
+#define CKA_PUBLIC_EXPONENT 0x00000122
+#define CKA_PRIVATE_EXPONENT 0x00000123
+#define CKA_PRIME_1 0x00000124
+#define CKA_PRIME_2 0x00000125
+#define CKA_EXPONENT_1 0x00000126
+#define CKA_EXPONENT_2 0x00000127
+#define CKA_COEFFICIENT 0x00000128
+#define CKA_PRIME 0x00000130
+#define CKA_SUBPRIME 0x00000131
+#define CKA_BASE 0x00000132
+
+/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
+#define CKA_PRIME_BITS 0x00000133
+#define CKA_SUBPRIME_BITS 0x00000134
+#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
+/* (To retain backwards-compatibility) */
+
+#define CKA_VALUE_BITS 0x00000160
+#define CKA_VALUE_LEN 0x00000161
+
+/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
+ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
+ * and CKA_EC_POINT are new for v2.0 */
+#define CKA_EXTRACTABLE 0x00000162
+#define CKA_LOCAL 0x00000163
+#define CKA_NEVER_EXTRACTABLE 0x00000164
+#define CKA_ALWAYS_SENSITIVE 0x00000165
+
+/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
+#define CKA_KEY_GEN_MECHANISM 0x00000166
+
+#define CKA_MODIFIABLE 0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS 0x00000180
+#define CKA_EC_PARAMS 0x00000180
+
+#define CKA_EC_POINT 0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+ * are new for v2.10. Deprecated in v2.11 and onwards. */
+#define CKA_SECONDARY_AUTH 0x00000200
+#define CKA_AUTH_PIN_FLAGS 0x00000201
+
+/* CKA_ALWAYS_AUTHENTICATE ...
+ * CKA_UNWRAP_TEMPLATE are new for v2.20 */
+#define CKA_ALWAYS_AUTHENTICATE 0x00000202
+
+#define CKA_WRAP_WITH_TRUSTED 0x00000210
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212)
+
+/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_HW_FEATURE_TYPE 0x00000300
+#define CKA_RESET_ON_INIT 0x00000301
+#define CKA_HAS_RESET 0x00000302
+
+/* The following attributes are new for v2.20 */
+#define CKA_PIXEL_X 0x00000400
+#define CKA_PIXEL_Y 0x00000401
+#define CKA_RESOLUTION 0x00000402
+#define CKA_CHAR_ROWS 0x00000403
+#define CKA_CHAR_COLUMNS 0x00000404
+#define CKA_COLOR 0x00000405
+#define CKA_BITS_PER_PIXEL 0x00000406
+#define CKA_CHAR_SETS 0x00000480
+#define CKA_ENCODING_METHODS 0x00000481
+#define CKA_MIME_TYPES 0x00000482
+#define CKA_MECHANISM_TYPE 0x00000500
+#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501
+#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502
+#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600)
+
+#define CKA_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+ CK_ATTRIBUTE_TYPE type;
+ CK_VOID_PTR pValue;
+
+ /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulValueLen; /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+ CK_CHAR year[4]; /* the year ("1900" - "9999") */
+ CK_CHAR month[2]; /* the month ("01" - "12") */
+ CK_CHAR day[2]; /* the day ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
+#define CKM_RSA_PKCS 0x00000001
+#define CKM_RSA_9796 0x00000002
+#define CKM_RSA_X_509 0x00000003
+
+/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
+ * are new for v2.0. They are mechanisms which hash and sign */
+#define CKM_MD2_RSA_PKCS 0x00000004
+#define CKM_MD5_RSA_PKCS 0x00000005
+#define CKM_SHA1_RSA_PKCS 0x00000006
+
+/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
+ * CKM_RSA_PKCS_OAEP are new for v2.10 */
+#define CKM_RIPEMD128_RSA_PKCS 0x00000007
+#define CKM_RIPEMD160_RSA_PKCS 0x00000008
+#define CKM_RSA_PKCS_OAEP 0x00000009
+
+/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
+ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
+#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
+#define CKM_RSA_X9_31 0x0000000B
+#define CKM_SHA1_RSA_X9_31 0x0000000C
+#define CKM_RSA_PKCS_PSS 0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010
+#define CKM_DSA 0x00000011
+#define CKM_DSA_SHA1 0x00000012
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
+#define CKM_DH_PKCS_DERIVE 0x00000021
+
+/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
+ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
+ * v2.11 */
+#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030
+#define CKM_X9_42_DH_DERIVE 0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032
+#define CKM_X9_42_MQV_DERIVE 0x00000033
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_RSA_PKCS 0x00000040
+#define CKM_SHA384_RSA_PKCS 0x00000041
+#define CKM_SHA512_RSA_PKCS 0x00000042
+#define CKM_SHA256_RSA_PKCS_PSS 0x00000043
+#define CKM_SHA384_RSA_PKCS_PSS 0x00000044
+#define CKM_SHA512_RSA_PKCS_PSS 0x00000045
+
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224_RSA_PKCS 0x00000046
+#define CKM_SHA224_RSA_PKCS_PSS 0x00000047
+
+#define CKM_RC2_KEY_GEN 0x00000100
+#define CKM_RC2_ECB 0x00000101
+#define CKM_RC2_CBC 0x00000102
+#define CKM_RC2_MAC 0x00000103
+
+/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
+#define CKM_RC2_MAC_GENERAL 0x00000104
+#define CKM_RC2_CBC_PAD 0x00000105
+
+#define CKM_RC4_KEY_GEN 0x00000110
+#define CKM_RC4 0x00000111
+#define CKM_DES_KEY_GEN 0x00000120
+#define CKM_DES_ECB 0x00000121
+#define CKM_DES_CBC 0x00000122
+#define CKM_DES_MAC 0x00000123
+
+/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
+#define CKM_DES_MAC_GENERAL 0x00000124
+#define CKM_DES_CBC_PAD 0x00000125
+
+#define CKM_DES2_KEY_GEN 0x00000130
+#define CKM_DES3_KEY_GEN 0x00000131
+#define CKM_DES3_ECB 0x00000132
+#define CKM_DES3_CBC 0x00000133
+#define CKM_DES3_MAC 0x00000134
+
+/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
+ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
+ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
+#define CKM_DES3_MAC_GENERAL 0x00000135
+#define CKM_DES3_CBC_PAD 0x00000136
+#define CKM_CDMF_KEY_GEN 0x00000140
+#define CKM_CDMF_ECB 0x00000141
+#define CKM_CDMF_CBC 0x00000142
+#define CKM_CDMF_MAC 0x00000143
+#define CKM_CDMF_MAC_GENERAL 0x00000144
+#define CKM_CDMF_CBC_PAD 0x00000145
+
+/* the following four DES mechanisms are new for v2.20 */
+#define CKM_DES_OFB64 0x00000150
+#define CKM_DES_OFB8 0x00000151
+#define CKM_DES_CFB64 0x00000152
+#define CKM_DES_CFB8 0x00000153
+
+#define CKM_MD2 0x00000200
+
+/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD2_HMAC 0x00000201
+#define CKM_MD2_HMAC_GENERAL 0x00000202
+
+#define CKM_MD5 0x00000210
+
+/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD5_HMAC 0x00000211
+#define CKM_MD5_HMAC_GENERAL 0x00000212
+
+#define CKM_SHA_1 0x00000220
+
+/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
+#define CKM_SHA_1_HMAC 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL 0x00000222
+
+/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC,
+ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
+ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
+#define CKM_RIPEMD128 0x00000230
+#define CKM_RIPEMD128_HMAC 0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232
+#define CKM_RIPEMD160 0x00000240
+#define CKM_RIPEMD160_HMAC 0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256 0x00000250
+#define CKM_SHA256_HMAC 0x00000251
+#define CKM_SHA256_HMAC_GENERAL 0x00000252
+#define CKM_SHA384 0x00000260
+#define CKM_SHA384_HMAC 0x00000261
+#define CKM_SHA384_HMAC_GENERAL 0x00000262
+#define CKM_SHA512 0x00000270
+#define CKM_SHA512_HMAC 0x00000271
+#define CKM_SHA512_HMAC_GENERAL 0x00000272
+
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224 0x00000255
+#define CKM_SHA224_HMAC 0x00000256
+#define CKM_SHA224_HMAC_GENERAL 0x00000257
+
+/* All of the following mechanisms are new for v2.0 */
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST_KEY_GEN 0x00000300
+#define CKM_CAST_ECB 0x00000301
+#define CKM_CAST_CBC 0x00000302
+#define CKM_CAST_MAC 0x00000303
+#define CKM_CAST_MAC_GENERAL 0x00000304
+#define CKM_CAST_CBC_PAD 0x00000305
+#define CKM_CAST3_KEY_GEN 0x00000310
+#define CKM_CAST3_ECB 0x00000311
+#define CKM_CAST3_CBC 0x00000312
+#define CKM_CAST3_MAC 0x00000313
+#define CKM_CAST3_MAC_GENERAL 0x00000314
+#define CKM_CAST3_CBC_PAD 0x00000315
+#define CKM_CAST5_KEY_GEN 0x00000320
+#define CKM_CAST128_KEY_GEN 0x00000320
+#define CKM_CAST5_ECB 0x00000321
+#define CKM_CAST128_ECB 0x00000321
+#define CKM_CAST5_CBC 0x00000322
+#define CKM_CAST128_CBC 0x00000322
+#define CKM_CAST5_MAC 0x00000323
+#define CKM_CAST128_MAC 0x00000323
+#define CKM_CAST5_MAC_GENERAL 0x00000324
+#define CKM_CAST128_MAC_GENERAL 0x00000324
+#define CKM_CAST5_CBC_PAD 0x00000325
+#define CKM_CAST128_CBC_PAD 0x00000325
+#define CKM_RC5_KEY_GEN 0x00000330
+#define CKM_RC5_ECB 0x00000331
+#define CKM_RC5_CBC 0x00000332
+#define CKM_RC5_MAC 0x00000333
+#define CKM_RC5_MAC_GENERAL 0x00000334
+#define CKM_RC5_CBC_PAD 0x00000335
+#define CKM_IDEA_KEY_GEN 0x00000340
+#define CKM_IDEA_ECB 0x00000341
+#define CKM_IDEA_CBC 0x00000342
+#define CKM_IDEA_MAC 0x00000343
+#define CKM_IDEA_MAC_GENERAL 0x00000344
+#define CKM_IDEA_CBC_PAD 0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363
+#define CKM_XOR_BASE_AND_DATA 0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372
+
+/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
+ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
+ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377
+
+/* CKM_TLS_PRF is new for v2.20 */
+#define CKM_TLS_PRF 0x00000378
+
+#define CKM_SSL3_MD5_MAC 0x00000380
+#define CKM_SSL3_SHA1_MAC 0x00000381
+#define CKM_MD5_KEY_DERIVATION 0x00000390
+#define CKM_MD2_KEY_DERIVATION 0x00000391
+#define CKM_SHA1_KEY_DERIVATION 0x00000392
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_KEY_DERIVATION 0x00000393
+#define CKM_SHA384_KEY_DERIVATION 0x00000394
+#define CKM_SHA512_KEY_DERIVATION 0x00000395
+
+/* CKM_SHA224 new for v2.20 amendment 3 */
+#define CKM_SHA224_KEY_DERIVATION 0x00000396
+
+#define CKM_PBE_MD2_DES_CBC 0x000003A0
+#define CKM_PBE_MD5_DES_CBC 0x000003A1
+#define CKM_PBE_MD5_CAST_CBC 0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC 0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC 0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC 0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5
+#define CKM_PBE_SHA1_RC4_128 0x000003A6
+#define CKM_PBE_SHA1_RC4_40 0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB
+
+/* CKM_PKCS5_PBKD2 is new for v2.10 */
+#define CKM_PKCS5_PBKD2 0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0
+
+/* WTLS mechanisms are new for v2.20 */
+#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0
+#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2
+#define CKM_WTLS_PRF 0x000003D3
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5
+
+#define CKM_KEY_WRAP_LYNKS 0x00000400
+#define CKM_KEY_WRAP_SET_OAEP 0x00000401
+
+/* CKM_CMS_SIG is new for v2.20 */
+#define CKM_CMS_SIG 0x00000500
+
+/* Fortezza mechanisms */
+#define CKM_SKIPJACK_KEY_GEN 0x00001000
+#define CKM_SKIPJACK_ECB64 0x00001001
+#define CKM_SKIPJACK_CBC64 0x00001002
+#define CKM_SKIPJACK_OFB64 0x00001003
+#define CKM_SKIPJACK_CFB64 0x00001004
+#define CKM_SKIPJACK_CFB32 0x00001005
+#define CKM_SKIPJACK_CFB16 0x00001006
+#define CKM_SKIPJACK_CFB8 0x00001007
+#define CKM_SKIPJACK_WRAP 0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009
+#define CKM_SKIPJACK_RELAYX 0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN 0x00001010
+#define CKM_KEA_KEY_DERIVE 0x00001011
+#define CKM_FORTEZZA_TIMESTAMP 0x00001020
+#define CKM_BATON_KEY_GEN 0x00001030
+#define CKM_BATON_ECB128 0x00001031
+#define CKM_BATON_ECB96 0x00001032
+#define CKM_BATON_CBC128 0x00001033
+#define CKM_BATON_COUNTER 0x00001034
+#define CKM_BATON_SHUFFLE 0x00001035
+#define CKM_BATON_WRAP 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040
+#define CKM_EC_KEY_PAIR_GEN 0x00001040
+
+#define CKM_ECDSA 0x00001041
+#define CKM_ECDSA_SHA1 0x00001042
+
+/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
+ * are new for v2.11 */
+#define CKM_ECDH1_DERIVE 0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051
+#define CKM_ECMQV_DERIVE 0x00001052
+
+#define CKM_JUNIPER_KEY_GEN 0x00001060
+#define CKM_JUNIPER_ECB128 0x00001061
+#define CKM_JUNIPER_CBC128 0x00001062
+#define CKM_JUNIPER_COUNTER 0x00001063
+#define CKM_JUNIPER_SHUFFLE 0x00001064
+#define CKM_JUNIPER_WRAP 0x00001065
+#define CKM_FASTHASH 0x00001070
+
+/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
+ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
+ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
+ * new for v2.11 */
+#define CKM_AES_KEY_GEN 0x00001080
+#define CKM_AES_ECB 0x00001081
+#define CKM_AES_CBC 0x00001082
+#define CKM_AES_MAC 0x00001083
+#define CKM_AES_MAC_GENERAL 0x00001084
+#define CKM_AES_CBC_PAD 0x00001085
+/* new for v2.20 amendment 3 */
+#define CKM_AES_CTR 0x00001086
+/* new for v2.30 */
+#define CKM_AES_GCM 0x00001087
+#define CKM_AES_CCM 0x00001088
+#define CKM_AES_CTS 0x00001089
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKM_BLOWFISH_KEY_GEN 0x00001090
+#define CKM_BLOWFISH_CBC 0x00001091
+#define CKM_TWOFISH_KEY_GEN 0x00001092
+#define CKM_TWOFISH_CBC 0x00001093
+
+/* Camellia is proposed for v2.20 Amendment 3 */
+#define CKM_CAMELLIA_KEY_GEN 0x00000550
+#define CKM_CAMELLIA_ECB 0x00000551
+#define CKM_CAMELLIA_CBC 0x00000552
+#define CKM_CAMELLIA_MAC 0x00000553
+#define CKM_CAMELLIA_MAC_GENERAL 0x00000554
+#define CKM_CAMELLIA_CBC_PAD 0x00000555
+#define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556
+#define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557
+
+#define CKM_SEED_KEY_GEN 0x00000650
+#define CKM_SEED_ECB 0x00000651
+#define CKM_SEED_CBC 0x00000652
+#define CKM_SEED_MAC 0x00000653
+#define CKM_SEED_MAC_GENERAL 0x00000654
+#define CKM_SEED_CBC_PAD 0x00000655
+#define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656
+#define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657
+
+/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */
+#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100
+#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101
+#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102
+#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103
+#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104
+#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105
+
+#define CKM_DSA_PARAMETER_GEN 0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002
+
+#define CKM_VENDOR_DEFINED 0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism */
+typedef struct CK_MECHANISM {
+ CK_MECHANISM_TYPE mechanism;
+ CK_VOID_PTR pParameter;
+
+ /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulParameterLen; /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+ CK_ULONG ulMinKeySize;
+ CK_ULONG ulMaxKeySize;
+ CK_FLAGS flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ * Bit Flag Mask Meaning */
+#define CKF_HW 0x00000001 /* performed by HW */
+
+/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
+ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
+ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
+ * and CKF_DERIVE are new for v2.0. They specify whether or not
+ * a mechanism can be used for a particular task */
+#define CKF_ENCRYPT 0x00000100
+#define CKF_DECRYPT 0x00000200
+#define CKF_DIGEST 0x00000400
+#define CKF_SIGN 0x00000800
+#define CKF_SIGN_RECOVER 0x00001000
+#define CKF_VERIFY 0x00002000
+#define CKF_VERIFY_RECOVER 0x00004000
+#define CKF_GENERATE 0x00008000
+#define CKF_GENERATE_KEY_PAIR 0x00010000
+#define CKF_WRAP 0x00020000
+#define CKF_UNWRAP 0x00040000
+#define CKF_DERIVE 0x00080000
+
+/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
+ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
+ * describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P 0x00100000
+#define CKF_EC_F_2M 0x00200000
+#define CKF_EC_ECPARAMETERS 0x00400000
+#define CKF_EC_NAMEDCURVE 0x00800000
+#define CKF_EC_UNCOMPRESS 0x01000000
+#define CKF_EC_COMPRESS 0x02000000
+
+#define CKF_EXTENSION 0x80000000 /* FALSE for this version */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * PKCS #11 function */
+/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_RV;
+
+#define CKR_OK 0x00000000
+#define CKR_CANCEL 0x00000001
+#define CKR_HOST_MEMORY 0x00000002
+#define CKR_SLOT_ID_INVALID 0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
+#define CKR_GENERAL_ERROR 0x00000005
+#define CKR_FUNCTION_FAILED 0x00000006
+
+/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
+ * and CKR_CANT_LOCK are new for v2.01 */
+#define CKR_ARGUMENTS_BAD 0x00000007
+#define CKR_NO_EVENT 0x00000008
+#define CKR_NEED_TO_CREATE_THREADS 0x00000009
+#define CKR_CANT_LOCK 0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY 0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE 0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013
+#define CKR_DATA_INVALID 0x00000020
+#define CKR_DATA_LEN_RANGE 0x00000021
+#define CKR_DEVICE_ERROR 0x00000030
+#define CKR_DEVICE_MEMORY 0x00000031
+#define CKR_DEVICE_REMOVED 0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID 0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041
+#define CKR_FUNCTION_CANCELED 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL 0x00000051
+
+/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
+#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054
+
+#define CKR_KEY_HANDLE_INVALID 0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE 0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT 0x00000063
+
+/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
+ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
+ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
+ * v2.0 */
+#define CKR_KEY_NOT_NEEDED 0x00000064
+#define CKR_KEY_CHANGED 0x00000065
+#define CKR_KEY_NEEDED 0x00000066
+#define CKR_KEY_INDIGESTIBLE 0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068
+#define CKR_KEY_NOT_WRAPPABLE 0x00000069
+#define CKR_KEY_UNEXTRACTABLE 0x0000006A
+
+#define CKR_MECHANISM_INVALID 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID 0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID 0x00000082
+#define CKR_OPERATION_ACTIVE 0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED 0x00000091
+#define CKR_PIN_INCORRECT 0x000000A0
+#define CKR_PIN_INVALID 0x000000A1
+#define CKR_PIN_LEN_RANGE 0x000000A2
+
+/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
+#define CKR_PIN_EXPIRED 0x000000A3
+#define CKR_PIN_LOCKED 0x000000A4
+
+#define CKR_SESSION_CLOSED 0x000000B0
+#define CKR_SESSION_COUNT 0x000000B1
+#define CKR_SESSION_HANDLE_INVALID 0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4
+#define CKR_SESSION_READ_ONLY 0x000000B5
+#define CKR_SESSION_EXISTS 0x000000B6
+
+/* CKR_SESSION_READ_ONLY_EXISTS and
+ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
+#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8
+
+#define CKR_SIGNATURE_INVALID 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE 0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE 0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT 0x000000D1
+#define CKR_TOKEN_NOT_PRESENT 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN 0x00000100
+#define CKR_USER_NOT_LOGGED_IN 0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102
+#define CKR_USER_TYPE_INVALID 0x00000103
+
+/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
+ * are new to v2.01 */
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104
+#define CKR_USER_TOO_MANY_TYPES 0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID 0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120
+
+/* These are new to v2.0 */
+#define CKR_RANDOM_NO_RNG 0x00000121
+
+/* These are new to v2.11 */
+#define CKR_DOMAIN_PARAMS_INVALID 0x00000130
+
+/* These are new to v2.0 */
+#define CKR_BUFFER_TOO_SMALL 0x00000150
+#define CKR_SAVED_STATE_INVALID 0x00000160
+#define CKR_INFORMATION_SENSITIVE 0x00000170
+#define CKR_STATE_UNSAVEABLE 0x00000180
+
+/* These are new to v2.01 */
+#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191
+#define CKR_MUTEX_BAD 0x000001A0
+#define CKR_MUTEX_NOT_LOCKED 0x000001A1
+
+/* This is new to v2.20 */
+#define CKR_FUNCTION_REJECTED 0x00000200
+
+#define CKR_VENDOR_DEFINED 0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a PKCS #11 spec
+ * version and pointers of appropriate types to all the
+ * PKCS #11 functions */
+/* CK_FUNCTION_LIST is new for v2.0 */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+ CK_CREATEMUTEX CreateMutex;
+ CK_DESTROYMUTEX DestroyMutex;
+ CK_LOCKMUTEX LockMutex;
+ CK_UNLOCKMUTEX UnlockMutex;
+ CK_FLAGS flags;
+ /* The official PKCS #11 spec does not have a 'LibraryParameters' field, but
+ * a reserved field. NSS needs a way to pass instance-specific information
+ * to the library (like where to find its config files, etc). This
+ * information is usually provided by the installer and passed uninterpreted
+ * by NSS to the library, though NSS does know the specifics of the softoken
+ * version of this parameter. Most compliant PKCS#11 modules expect this
+ * parameter to be NULL, and will return CKR_ARGUMENTS_BAD from
+ * C_Initialize if Library parameters is supplied. */
+ CK_CHAR_PTR *LibraryParameters;
+ /* This field is only present if the LibraryParameters is not NULL. It must
+ * be NULL in all cases */
+ CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK 0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK 1
+
+/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512
+ * are new for v2.20 */
+#define CKG_MGF1_SHA1 0x00000001
+#define CKG_MGF1_SHA256 0x00000002
+#define CKG_MGF1_SHA384 0x00000003
+#define CKG_MGF1_SHA512 0x00000004
+
+/* v2.20 amendment 3 */
+#define CKG_MGF1_SHA224 0x00000005
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED 0x00000001
+
+/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ CK_VOID_PTR pSourceData;
+ CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_ULONG sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+/* CK_EC_KDF_TYPE is new for v2.11. */
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL 0x00000001
+#define CKD_SHA1_KDF 0x00000002
+#define CKD_SHA224_KDF 0x00000005
+#define CKD_SHA256_KDF 0x00000006
+#define CKD_SHA384_KDF 0x00000007
+#define CKD_SHA512_KDF 0x00000008
+
+/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+
+/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* The following X9.42 DH key derivation functions are defined
+ (besides CKD_NULL already defined : */
+#define CKD_SHA1_KDF_ASN1 0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+
+/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
+typedef struct CK_KEA_DERIVE_PARAMS {
+ CK_BBOOL isSender;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pRandomB;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+ /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+
+ CK_BYTE iv[8]; /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+/* CK_RC5_PARAMS is new for v2.0 */
+typedef struct CK_RC5_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+/* CK_RC5_CBC_PARAMS is new for v2.0 */
+typedef struct CK_RC5_CBC_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_BYTE_PTR pIv; /* pointer to IV */
+ CK_ULONG ulIvLen; /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
+ * the MAC */
+/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[8];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_AES_CTR_PARAMS is new for PKCS #11 v2.20 amendment 3 */
+typedef struct CK_AES_CTR_PARAMS {
+ CK_ULONG ulCounterBits;
+ CK_BYTE cb[16];
+} CK_AES_CTR_PARAMS;
+
+typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR;
+
+/* CK_GCM_PARAMS is new for version 2.30 */
+typedef struct CK_GCM_PARAMS {
+ CK_BYTE_PTR pIv;
+ CK_ULONG ulIvLen;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulTagBits;
+} CK_GCM_PARAMS;
+
+typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR;
+
+/* CK_CCM_PARAMS is new for version 2.30 */
+typedef struct CK_CCM_PARAMS {
+ CK_ULONG ulDataLen;
+ CK_BYTE_PTR pNonce;
+ CK_ULONG ulNonceLen;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulMACLen;
+} CK_CCM_PARAMS;
+
+typedef CK_CCM_PARAMS CK_PTR CK_CCM_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pPassword;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPAndGLen;
+ CK_ULONG ulQLen;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pPrimeP;
+ CK_BYTE_PTR pBaseG;
+ CK_BYTE_PTR pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+ CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+ CK_ULONG ulOldWrappedXLen;
+ CK_BYTE_PTR pOldWrappedX;
+ CK_ULONG ulOldPasswordLen;
+ CK_BYTE_PTR pOldPassword;
+ CK_ULONG ulOldPublicDataLen;
+ CK_BYTE_PTR pOldPublicData;
+ CK_ULONG ulOldRandomLen;
+ CK_BYTE_PTR pOldRandomA;
+ CK_ULONG ulNewPasswordLen;
+ CK_BYTE_PTR pNewPassword;
+ CK_ULONG ulNewPublicDataLen;
+ CK_BYTE_PTR pNewPublicData;
+ CK_ULONG ulNewRandomLen;
+ CK_BYTE_PTR pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+ CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+ CK_BYTE_PTR pInitVector;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_ULONG ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+ CK_BYTE bBC; /* block contents byte */
+ CK_BYTE_PTR pX; /* extra data */
+ CK_ULONG ulXLen; /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+ CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hClientMacSecret;
+ CK_OBJECT_HANDLE hServerMacSecret;
+ CK_OBJECT_HANDLE hClientKey;
+ CK_OBJECT_HANDLE hServerKey;
+ CK_BYTE_PTR pIVClient;
+ CK_BYTE_PTR pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+/* CK_TLS_PRF_PARAMS is new for version 2.20 */
+typedef struct CK_TLS_PRF_PARAMS {
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+/* WTLS is new for version 2.20 */
+typedef struct CK_WTLS_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hMacSecret;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_ULONG ulSequenceNumber;
+ CK_BBOOL bIsExport;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+/* CMS is new for version 2.20 */
+typedef struct CK_CMS_SIG_PARAMS {
+ CK_OBJECT_HANDLE certificateHandle;
+ CK_MECHANISM_PTR pSigningMechanism;
+ CK_MECHANISM_PTR pDigestMechanism;
+ CK_UTF8CHAR_PTR pContentType;
+ CK_BYTE_PTR pRequestedAttributes;
+ CK_ULONG ulRequestedAttributesLen;
+ CK_BYTE_PTR pRequiredAttributes;
+ CK_ULONG ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+ CK_BYTE_PTR pData;
+ CK_ULONG ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+ CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+/* CK_EXTRACT_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+/* The following PRFs are defined in PKCS #5 v2.0. */
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED 0x00000001
+
+/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG_PTR ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+/* NSS Specific defines */
+
+/* defines that have been deprecated in 2.20, but maintained in our
+ * header file for backward compatibility */
+#define CKO_KG_PARAMETERS CKO_DOMAIN_PARAMETERS
+#define CKF_EC_FP CKF_EC_F_P
+/* new in v2.11 deprecated by 2.20 */
+#define CKR_KEY_PARAMS_INVALID 0x0000006B
+
+/* stuff that for historic reasons is in this header file but should have
+ * been in pkcs11n.h */
+#define CKK_INVALID_KEY_TYPE 0xffffffff
+
+#include "pkcs11n.h"
+
+/* undo packing */
+#include "pkcs11u.h"
+
+#endif
diff --git a/lib/util/pkcs11u.h b/lib/util/pkcs11u.h
new file mode 100644
index 000000000..f670094a9
--- /dev/null
+++ b/lib/util/pkcs11u.h
@@ -0,0 +1,20 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
+ * is granted provided that it is identified as "RSA Security Inc. Public-Key
+ * Cryptography Standards (PKCS)" in all material mentioning or referencing
+ * this document.
+ */
+/*
+ * reset any packing set by pkcs11p.h
+ */
+
+#if defined (_WIN32)
+#ifdef _MSC_VER
+#pragma warning(disable:4103)
+#endif
+#pragma pack(pop, cryptoki)
+#endif
+
diff --git a/lib/util/portreg.c b/lib/util/portreg.c
new file mode 100644
index 000000000..ba2b3ce91
--- /dev/null
+++ b/lib/util/portreg.c
@@ -0,0 +1,377 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * shexp.c: shell-like wildcard match routines
+ *
+ * See shexp.h for public documentation.
+ */
+
+#include "seccomon.h"
+#include "portreg.h"
+
+/* ----------------------------- shexp_valid ------------------------------ */
+
+
+static int
+_valid_subexp(const char *exp, char stop1, char stop2)
+{
+ register int x;
+ int nsc = 0; /* Number of special characters */
+ int np; /* Number of pipe characters in union */
+ int tld = 0; /* Number of tilde characters */
+
+ for (x = 0; exp[x] && (exp[x] != stop1) && (exp[x] != stop2); ++x) {
+ switch(exp[x]) {
+ case '~':
+ if(tld) /* at most one exclusion */
+ return INVALID_SXP;
+ if (stop1) /* no exclusions within unions */
+ return INVALID_SXP;
+ if (!exp[x+1]) /* exclusion cannot be last character */
+ return INVALID_SXP;
+ if (!x) /* exclusion cannot be first character */
+ return INVALID_SXP;
+ ++tld;
+ /* fall through */
+ case '*':
+ case '?':
+ case '$':
+ ++nsc;
+ break;
+ case '[':
+ ++nsc;
+ if((!exp[++x]) || (exp[x] == ']'))
+ return INVALID_SXP;
+ for(; exp[x] && (exp[x] != ']'); ++x) {
+ if(exp[x] == '\\' && !exp[++x])
+ return INVALID_SXP;
+ }
+ if(!exp[x])
+ return INVALID_SXP;
+ break;
+ case '(':
+ ++nsc;
+ if (stop1) /* no nested unions */
+ return INVALID_SXP;
+ np = -1;
+ do {
+ int t = _valid_subexp(&exp[++x], ')', '|');
+ if(t == 0 || t == INVALID_SXP)
+ return INVALID_SXP;
+ x+=t;
+ if(!exp[x])
+ return INVALID_SXP;
+ ++np;
+ } while (exp[x] == '|' );
+ if(np < 1) /* must be at least one pipe */
+ return INVALID_SXP;
+ break;
+ case ')':
+ case '|':
+ case ']':
+ return INVALID_SXP;
+ case '\\':
+ ++nsc;
+ if(!exp[++x])
+ return INVALID_SXP;
+ break;
+ default:
+ break;
+ }
+ }
+ if((!stop1) && (!nsc)) /* must be at least one special character */
+ return NON_SXP;
+ return ((exp[x] == stop1 || exp[x] == stop2) ? x : INVALID_SXP);
+}
+
+int
+PORT_RegExpValid(const char *exp)
+{
+ int x;
+
+ x = _valid_subexp(exp, '\0', '\0');
+ return (x < 0 ? x : VALID_SXP);
+}
+
+
+/* ----------------------------- shexp_match ----------------------------- */
+
+
+#define MATCH 0
+#define NOMATCH 1
+#define ABORTED -1
+
+static int
+_shexp_match(const char *str, const char *exp, PRBool case_insensitive,
+ unsigned int level);
+
+/* Count characters until we reach a NUL character or either of the
+ * two delimiter characters, stop1 or stop2. If we encounter a bracketed
+ * expression, look only for NUL or ']' inside it. Do not look for stop1
+ * or stop2 inside it. Return ABORTED if bracketed expression is unterminated.
+ * Handle all escaping.
+ * Return index in input string of first stop found, or ABORTED if not found.
+ * If "dest" is non-NULL, copy counted characters to it and NUL terminate.
+ */
+static int
+_scan_and_copy(const char *exp, char stop1, char stop2, char *dest)
+{
+ register int sx; /* source index */
+ register char cc;
+
+ for (sx = 0; (cc = exp[sx]) && cc != stop1 && cc != stop2; sx++) {
+ if (cc == '\\') {
+ if (!exp[++sx])
+ return ABORTED; /* should be impossible */
+ } else if (cc == '[') {
+ while ((cc = exp[++sx]) && cc != ']') {
+ if(cc == '\\' && !exp[++sx])
+ return ABORTED;
+ }
+ if (!cc)
+ return ABORTED; /* should be impossible */
+ }
+ }
+ if (dest && sx) {
+ /* Copy all but the closing delimiter. */
+ memcpy(dest, exp, sx);
+ dest[sx] = 0;
+ }
+ return cc ? sx : ABORTED; /* index of closing delimiter */
+}
+
+/* On input, exp[0] is the opening parenthesis of a union.
+ * See if any of the alternatives in the union matches as a pattern.
+ * The strategy is to take each of the alternatives, in turn, and append
+ * the rest of the expression (after the closing ')' that marks the end of
+ * this union) to that alternative, and then see if the resultant expression
+ * matches the input string. Repeat this until some alternative matches,
+ * or we have an abort.
+ */
+static int
+_handle_union(const char *str, const char *exp, PRBool case_insensitive,
+ unsigned int level)
+{
+ register int sx; /* source index */
+ int cp; /* source index of closing parenthesis */
+ int count;
+ int ret = NOMATCH;
+ char *e2;
+
+ /* Find the closing parenthesis that ends this union in the expression */
+ cp = _scan_and_copy(exp, ')', '\0', NULL);
+ if (cp == ABORTED || cp < 4) /* must be at least "(a|b" before ')' */
+ return ABORTED;
+ ++cp; /* now index of char after closing parenthesis */
+ e2 = (char *) PORT_Alloc(1 + strlen(exp));
+ if (!e2)
+ return ABORTED;
+ for (sx = 1; ; ++sx) {
+ /* Here, exp[sx] is one character past the preceding '(' or '|'. */
+ /* Copy everything up to the next delimiter to e2 */
+ count = _scan_and_copy(exp + sx, ')', '|', e2);
+ if (count == ABORTED || !count) {
+ ret = ABORTED;
+ break;
+ }
+ sx += count;
+ /* Append everything after closing parenthesis to e2. This is safe. */
+ strcpy(e2+count, exp+cp);
+ ret = _shexp_match(str, e2, case_insensitive, level + 1);
+ if (ret != NOMATCH || !exp[sx] || exp[sx] == ')')
+ break;
+ }
+ PORT_Free(e2);
+ if (sx < 2)
+ ret = ABORTED;
+ return ret;
+}
+
+/* returns 1 if val is in range from start..end, case insensitive. */
+static int
+_is_char_in_range(int start, int end, int val)
+{
+ char map[256];
+ memset(map, 0, sizeof map);
+ while (start <= end)
+ map[tolower(start++)] = 1;
+ return map[tolower(val)];
+}
+
+static int
+_shexp_match(const char *str, const char *exp, PRBool case_insensitive,
+ unsigned int level)
+{
+ register int x; /* input string index */
+ register int y; /* expression index */
+ int ret,neg;
+
+ if (level > 20) /* Don't let the stack get too deep. */
+ return ABORTED;
+ for(x = 0, y = 0; exp[y]; ++y, ++x) {
+ if((!str[x]) && (exp[y] != '$') && (exp[y] != '*')) {
+ return NOMATCH;
+ }
+ switch(exp[y]) {
+ case '$':
+ if(str[x])
+ return NOMATCH;
+ --x; /* we don't want loop to increment x */
+ break;
+ case '*':
+ while(exp[++y] == '*'){}
+ if(!exp[y])
+ return MATCH;
+ while(str[x]) {
+ ret = _shexp_match(&str[x++], &exp[y], case_insensitive,
+ level + 1);
+ switch(ret) {
+ case NOMATCH:
+ continue;
+ case ABORTED:
+ return ABORTED;
+ default:
+ return MATCH;
+ }
+ }
+ if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
+ return MATCH;
+ else
+ return NOMATCH;
+ case '[': {
+ int start, end = 0, i;
+ neg = ((exp[++y] == '^') && (exp[y+1] != ']'));
+ if (neg)
+ ++y;
+ i = y;
+ start = (unsigned char)(exp[i++]);
+ if (start == '\\')
+ start = (unsigned char)(exp[i++]);
+ if (isalnum(start) && exp[i++] == '-') {
+ end = (unsigned char)(exp[i++]);
+ if (end == '\\')
+ end = (unsigned char)(exp[i++]);
+ }
+ if (isalnum(end) && exp[i] == ']') {
+ /* This is a range form: a-b */
+ int val = (unsigned char)(str[x]);
+ if (end < start) { /* swap them */
+ start ^= end;
+ end ^= start;
+ start ^= end;
+ }
+ if (case_insensitive && isalpha(val)) {
+ val = _is_char_in_range(start, end, val);
+ if (neg == val)
+ return NOMATCH;
+ } else if (neg != ((val < start) || (val > end))) {
+ return NOMATCH;
+ }
+ y = i;
+ } else {
+ /* Not range form */
+ int matched = 0;
+ for (; exp[y] != ']'; y++) {
+ if (exp[y] == '\\')
+ ++y;
+ if(case_insensitive) {
+ matched |= (toupper(str[x]) == toupper(exp[y]));
+ } else {
+ matched |= (str[x] == exp[y]);
+ }
+ }
+ if (neg == matched)
+ return NOMATCH;
+ }
+ }
+ break;
+ case '(':
+ if (!exp[y+1])
+ return ABORTED;
+ return _handle_union(&str[x], &exp[y], case_insensitive, level);
+ case '?':
+ break;
+ case '|':
+ case ']':
+ case ')':
+ return ABORTED;
+ case '\\':
+ ++y;
+ /* fall through */
+ default:
+ if(case_insensitive) {
+ if(toupper(str[x]) != toupper(exp[y]))
+ return NOMATCH;
+ } else {
+ if(str[x] != exp[y])
+ return NOMATCH;
+ }
+ break;
+ }
+ }
+ return (str[x] ? NOMATCH : MATCH);
+}
+
+static int
+port_RegExpMatch(const char *str, const char *xp, PRBool case_insensitive)
+{
+ char *exp = 0;
+ int x, ret = MATCH;
+
+ if (!strchr(xp, '~'))
+ return _shexp_match(str, xp, case_insensitive, 0);
+
+ exp = PORT_Strdup(xp);
+ if(!exp)
+ return NOMATCH;
+
+ x = _scan_and_copy(exp, '~', '\0', NULL);
+ if (x != ABORTED && exp[x] == '~') {
+ exp[x++] = '\0';
+ ret = _shexp_match(str, &exp[x], case_insensitive, 0);
+ switch (ret) {
+ case NOMATCH: ret = MATCH; break;
+ case MATCH: ret = NOMATCH; break;
+ default: break;
+ }
+ }
+ if (ret == MATCH)
+ ret = _shexp_match(str, exp, case_insensitive, 0);
+
+ PORT_Free(exp);
+ return ret;
+}
+
+
+/* ------------------------------ shexp_cmp ------------------------------- */
+
+int
+PORT_RegExpSearch(const char *str, const char *exp)
+{
+ switch(PORT_RegExpValid(exp))
+ {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+ return (strcmp(exp,str) ? 1 : 0);
+ default:
+ return port_RegExpMatch(str, exp, PR_FALSE);
+ }
+}
+
+int
+PORT_RegExpCaseSearch(const char *str, const char *exp)
+{
+ switch(PORT_RegExpValid(exp))
+ {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+ return (PORT_Strcasecmp(exp,str) ? 1 : 0);
+ default:
+ return port_RegExpMatch(str, exp, PR_TRUE);
+ }
+}
+
diff --git a/lib/util/portreg.h b/lib/util/portreg.h
new file mode 100644
index 000000000..811f04539
--- /dev/null
+++ b/lib/util/portreg.h
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * shexp.h: Defines and prototypes for shell exp. match routines
+ *
+ * This routine will match a string with a shell expression. The expressions
+ * accepted are based loosely on the expressions accepted by zsh.
+ *
+ * o * matches anything
+ * o ? matches one character
+ * o \ will escape a special character
+ * o $ matches the end of the string
+ * Bracketed expressions:
+ * o [abc] matches one occurence of a, b, or c.
+ * o [^abc] matches any character except a, b, or c.
+ * To be matched between [ and ], these characters must be escaped: \ ]
+ * No other characters need be escaped between brackets.
+ * Unnecessary escaping is permitted.
+ * o [a-z] matches any character between a and z, inclusive.
+ * The two range-definition characters must be alphanumeric ASCII.
+ * If one is upper case and the other is lower case, then the ASCII
+ * non-alphanumeric characters between Z and a will also be in range.
+ * o [^a-z] matches any character except those between a and z, inclusive.
+ * These forms cannot be combined, e.g [a-gp-z] does not work.
+ * o Exclusions:
+ * As a top level, outter-most expression only, the expression
+ * foo~bar will match the expression foo, provided it does not also
+ * match the expression bar. Either expression or both may be a union.
+ * Except between brackets, any unescaped ~ is an exclusion.
+ * At most one exclusion is permitted.
+ * Exclusions cannot be nested (contain other exclusions).
+ * example: *~abc will match any string except abc
+ * o Unions:
+ * (foo|bar) will match either the expression foo, or the expression bar.
+ * At least one '|' separator is required. More are permitted.
+ * Expressions inside unions may not include unions or exclusions.
+ * Inside a union, to be matched and not treated as a special character,
+ * these characters must be escaped: \ ( | ) [ ~ except when they occur
+ * inside a bracketed expression, where only \ and ] require escaping.
+ *
+ * The public interface to these routines is documented below.
+ *
+ */
+
+#ifndef SHEXP_H
+#define SHEXP_H
+
+#include "utilrename.h"
+/*
+ * Requires that the macro MALLOC be set to a "safe" malloc that will
+ * exit if no memory is available.
+ */
+
+
+/* --------------------------- Public routines ---------------------------- */
+
+
+/*
+ * shexp_valid takes a shell expression exp as input. It returns:
+ *
+ * NON_SXP if exp is a standard string
+ * INVALID_SXP if exp is a shell expression, but invalid
+ * VALID_SXP if exp is a valid shell expression
+ */
+
+#define NON_SXP -1
+#define INVALID_SXP -2
+#define VALID_SXP 1
+
+SEC_BEGIN_PROTOS
+
+extern int PORT_RegExpValid(const char *exp);
+
+extern int PORT_RegExpSearch(const char *str, const char *exp);
+
+/* same as above but uses case insensitive search */
+extern int PORT_RegExpCaseSearch(const char *str, const char *exp);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/lib/util/quickder.c b/lib/util/quickder.c
new file mode 100644
index 000000000..2374ba29c
--- /dev/null
+++ b/lib/util/quickder.c
@@ -0,0 +1,897 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ Optimized ASN.1 DER decoder
+
+*/
+
+#include "secerr.h"
+#include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
+#include "secitem.h"
+
+/*
+ * simple definite-length ASN.1 decoder
+ */
+
+static unsigned char* definite_length_decoder(const unsigned char *buf,
+ const unsigned int length,
+ unsigned int *data_length,
+ PRBool includeTag)
+{
+ unsigned char tag;
+ unsigned int used_length= 0;
+ unsigned int data_len;
+
+ if (used_length >= length)
+ {
+ return NULL;
+ }
+ tag = buf[used_length++];
+
+ /* blow out when we come to the end */
+ if (tag == 0)
+ {
+ return NULL;
+ }
+
+ if (used_length >= length)
+ {
+ return NULL;
+ }
+ data_len = buf[used_length++];
+
+ if (data_len&0x80)
+ {
+ int len_count = data_len & 0x7f;
+
+ data_len = 0;
+
+ while (len_count-- > 0)
+ {
+ if (used_length >= length)
+ {
+ return NULL;
+ }
+ data_len = (data_len << 8) | buf[used_length++];
+ }
+ }
+
+ if (data_len > (length-used_length) )
+ {
+ return NULL;
+ }
+ if (includeTag) data_len += used_length;
+
+ *data_length = data_len;
+ return ((unsigned char*)buf + (includeTag ? 0 : used_length));
+}
+
+static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
+{
+ if ( (!src) || (!dest) || (!src->data && src->len) )
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (!src->len)
+ {
+ /* reaching the end of the buffer is not an error */
+ dest->data = NULL;
+ dest->len = 0;
+ return SECSuccess;
+ }
+
+ dest->data = definite_length_decoder(src->data, src->len, &dest->len,
+ includeTag);
+ if (dest->data == NULL)
+ {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ src->len -= (dest->data - src->data) + dest->len;
+ src->data = dest->data + dest->len;
+ return SECSuccess;
+}
+
+/* check if the actual component's type matches the type in the template */
+
+static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
+ SECItem* item, PRBool* match, void* dest)
+{
+ unsigned long kind = 0;
+ unsigned char tag = 0;
+
+ if ( (!item) || (!item->data && item->len) || (!templateEntry) || (!match) )
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (!item->len)
+ {
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ kind = templateEntry->kind;
+ tag = *(unsigned char*) item->data;
+
+ if ( ( (kind & SEC_ASN1_INLINE) ||
+ (kind & SEC_ASN1_POINTER) ) &&
+ (0 == (kind & SEC_ASN1_TAG_MASK) ) )
+ {
+ /* These cases are special because the template's "kind" does not
+ give us the information for the ASN.1 tag of the next item. It can
+ only be figured out from the subtemplate. */
+ if (!(kind & SEC_ASN1_OPTIONAL))
+ {
+ /* This is a required component. If there is a type mismatch,
+ the decoding of the subtemplate will fail, so assume this
+ is a match at the parent level and let it fail later. This
+ avoids a redundant check in matching cases */
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ else
+ {
+ /* optional component. This is the hard case. Now we need to
+ look at the subtemplate to get the expected kind */
+ const SEC_ASN1Template* subTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+ if (!subTemplate)
+ {
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ return SECFailure;
+ }
+ if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
+ (subTemplate->kind & SEC_ASN1_POINTER) )
+ {
+ /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
+ otherwise you may get a false positive due to the recursion
+ optimization above that always matches the type if the
+ component is required . Nesting these should never be
+ required, so that no one should miss this ability */
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ return SECFailure;
+ }
+ return MatchComponentType(subTemplate, item, match,
+ (void*)((char*)dest + templateEntry->offset));
+ }
+ }
+
+ if (kind & SEC_ASN1_CHOICE)
+ {
+ /* we need to check the component's tag against each choice's tag */
+ /* XXX it would be nice to save the index of the choice here so that
+ DecodeChoice wouldn't have to do this again. However, due to the
+ recursivity of MatchComponentType, we don't know if we are in a
+ required or optional component, so we can't write anywhere in
+ the destination within this function */
+ unsigned choiceIndex = 1;
+ const SEC_ASN1Template* choiceEntry;
+ while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
+ {
+ if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
+ (void*)((char*)dest + choiceEntry->offset))) &&
+ (PR_TRUE == *match) )
+ {
+ return SECSuccess;
+ }
+ }
+ /* no match, caller must decide if this is BAD DER, or not. */
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ if (kind & SEC_ASN1_ANY)
+ {
+ /* SEC_ASN1_ANY always matches */
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+
+ if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
+ (!(kind & SEC_ASN1_EXPLICIT)) &&
+ ( ( (kind & SEC_ASN1_SAVE) ||
+ (kind & SEC_ASN1_SKIP) ) &&
+ (!(kind & SEC_ASN1_OPTIONAL))
+ )
+ )
+ {
+ /* when saving or skipping a required component, a type is not
+ required in the template. This is for legacy support of
+ SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
+ deprecate these usages and always require a type, as this
+ disables type checking, and effectively forbids us from
+ transparently ignoring optional components we aren't aware of */
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+
+ /* first, do a class check */
+ if ( (tag & SEC_ASN1_CLASS_MASK) !=
+ (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
+ {
+#ifdef DEBUG
+ /* this is only to help debugging of the decoder in case of problems */
+ unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
+ unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
+ tagclass = tagclass;
+ expectedclass = expectedclass;
+#endif
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ /* now do a tag check */
+ if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
+ (tag & SEC_ASN1_TAGNUM_MASK))
+ {
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ /* now, do a method check. This depends on the class */
+ switch (tag & SEC_ASN1_CLASS_MASK)
+ {
+ case SEC_ASN1_UNIVERSAL:
+ /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
+ primitive or constructed based on the tag */
+ switch (tag & SEC_ASN1_TAGNUM_MASK)
+ {
+ case SEC_ASN1_SEQUENCE:
+ case SEC_ASN1_SET:
+ case SEC_ASN1_EMBEDDED_PDV:
+ /* this component must be a constructed type */
+ /* XXX add any new universal constructed type here */
+ if (tag & SEC_ASN1_CONSTRUCTED)
+ {
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ break;
+
+ default:
+ /* this component must be a primitive type */
+ if (! (tag & SEC_ASN1_CONSTRUCTED))
+ {
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ break;
+ }
+ break;
+
+ default:
+ /* for all other classes, we check the method based on the template */
+ if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
+ (tag & SEC_ASN1_METHOD_MASK) )
+ {
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ /* method does not match between template and component */
+ break;
+ }
+
+ *match = PR_FALSE;
+ return SECSuccess;
+}
+
+#ifdef DEBUG
+
+static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
+{
+ SECStatus rv = SECSuccess;
+ const SEC_ASN1Template* sequenceEntry = NULL;
+ unsigned long seqIndex = 0;
+ unsigned long lastEntryIndex = 0;
+ unsigned long ambiguityIndex = 0;
+ PRBool foundAmbiguity = PR_FALSE;
+
+ do
+ {
+ sequenceEntry = &sequenceTemplate[seqIndex++];
+ if (sequenceEntry->kind)
+ {
+ /* ensure that we don't have an optional component of SEC_ASN1_ANY
+ in the middle of the sequence, since we could not handle it */
+ /* XXX this function needs to dig into the subtemplates to find
+ the next tag */
+ if ( (PR_FALSE == foundAmbiguity) &&
+ (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
+ (sequenceEntry->kind & SEC_ASN1_ANY) )
+ {
+ foundAmbiguity = PR_TRUE;
+ ambiguityIndex = seqIndex - 1;
+ }
+ }
+ } while (sequenceEntry->kind);
+
+ lastEntryIndex = seqIndex - 2;
+
+ if (PR_FALSE != foundAmbiguity)
+ {
+ if (ambiguityIndex < lastEntryIndex)
+ {
+ /* ambiguity can only be tolerated on the last entry */
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ rv = SECFailure;
+ }
+ }
+
+ /* XXX also enforce ASN.1 requirement that tags be
+ distinct for consecutive optional components */
+
+ return rv;
+}
+
+#endif
+
+static SECStatus DecodeItem(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag);
+
+static SECStatus DecodeSequence(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem source;
+ SECItem sequence;
+ const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
+ const SEC_ASN1Template* sequenceEntry = NULL;
+ unsigned long seqindex = 0;
+
+#ifdef DEBUG
+ /* for a sequence, we need to validate the template. */
+ rv = CheckSequenceTemplate(sequenceTemplate);
+#endif
+
+ source = *src;
+
+ /* get the sequence */
+ if (SECSuccess == rv)
+ {
+ rv = GetItem(&source, &sequence, PR_FALSE);
+ }
+
+ /* process it */
+ if (SECSuccess == rv)
+ do
+ {
+ sequenceEntry = &sequenceTemplate[seqindex++];
+ if ( (sequenceEntry && sequenceEntry->kind) &&
+ (sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
+ {
+ rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
+ }
+ } while ( (SECSuccess == rv) &&
+ (sequenceEntry->kind &&
+ sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
+ /* we should have consumed all the bytes in the sequence by now
+ unless the caller doesn't care about the rest of the sequence */
+ if (SECSuccess == rv && sequence.len &&
+ sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
+ {
+ /* it isn't 100% clear whether this is a bad DER or a bad template.
+ The problem is that logically, they don't match - there is extra
+ data in the DER that the template doesn't know about */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ }
+
+ return rv;
+}
+
+static SECStatus DecodeInline(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+ const SEC_ASN1Template* inlineTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+ return DecodeItem((void*)((char*)dest + templateEntry->offset),
+ inlineTemplate, src, arena, checkTag);
+}
+
+static SECStatus DecodePointer(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+ const SEC_ASN1Template* ptrTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+ void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
+ *(void**)((char*)dest + templateEntry->offset) = subdata;
+ if (subdata)
+ {
+ return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
+ }
+ else
+ {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+}
+
+static SECStatus DecodeImplicit(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ if (templateEntry->kind & SEC_ASN1_POINTER)
+ {
+ return DecodePointer((void*)((char*)dest ),
+ templateEntry, src, arena, PR_FALSE);
+ }
+ else
+ {
+ return DecodeInline((void*)((char*)dest ),
+ templateEntry, src, arena, PR_FALSE);
+ }
+}
+
+static SECStatus DecodeChoice(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem choice;
+ const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
+ const SEC_ASN1Template* choiceEntry = NULL;
+ unsigned long choiceindex = 0;
+
+ /* XXX for a choice component, we should validate the template to make
+ sure the tags are distinct, in debug builds. This hasn't been
+ implemented yet */
+ /* rv = CheckChoiceTemplate(sequenceTemplate); */
+
+ /* process it */
+ do
+ {
+ choice = *src;
+ choiceEntry = &choiceTemplate[choiceindex++];
+ if (choiceEntry->kind)
+ {
+ rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
+ }
+ } while ( (SECFailure == rv) && (choiceEntry->kind));
+
+ if (SECFailure == rv)
+ {
+ /* the component didn't match any of the choices */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ }
+ else
+ {
+ /* set the type in the union here */
+ int *which = (int *)((char *)dest + templateEntry->offset);
+ *which = (int)choiceEntry->size;
+ }
+
+ /* we should have consumed all the bytes by now */
+ /* fail if we have not */
+ if (SECSuccess == rv && choice.len)
+ {
+ /* there is extra data that isn't listed in the template */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+static SECStatus DecodeGroup(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem source;
+ SECItem group;
+ PRUint32 totalEntries = 0;
+ PRUint32 entryIndex = 0;
+ void** entries = NULL;
+
+ const SEC_ASN1Template* subTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+
+ source = *src;
+
+ /* get the group */
+ if (SECSuccess == rv)
+ {
+ rv = GetItem(&source, &group, PR_FALSE);
+ }
+
+ /* XXX we should check the subtemplate in debug builds */
+ if (SECSuccess == rv)
+ {
+ /* first, count the number of entries. Benchmarking showed that this
+ counting pass is more efficient than trying to allocate entries as
+ we read the DER, even if allocating many entries at a time
+ */
+ SECItem counter = group;
+ do
+ {
+ SECItem anitem;
+ rv = GetItem(&counter, &anitem, PR_TRUE);
+ if (SECSuccess == rv && (anitem.len) )
+ {
+ totalEntries++;
+ }
+ } while ( (SECSuccess == rv) && (counter.len) );
+
+ if (SECSuccess == rv)
+ {
+ /* allocate room for pointer array and entries */
+ /* we want to allocate the array even if there is 0 entry */
+ entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
+ (totalEntries + 1 ) + /* the extra one is for NULL termination */
+ subTemplate->size*totalEntries);
+
+ if (entries)
+ {
+ entries[totalEntries] = NULL; /* terminate the array */
+ }
+ else
+ {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ rv = SECFailure;
+ }
+ if (SECSuccess == rv)
+ {
+ void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
+ /* and fix the pointers in the array */
+ PRUint32 entriesIndex = 0;
+ for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
+ {
+ entries[entriesIndex] =
+ (char*)entriesData + (subTemplate->size*entriesIndex);
+ }
+ }
+ }
+ }
+
+ if (SECSuccess == rv && totalEntries)
+ do
+ {
+ if (!(entryIndex<totalEntries))
+ {
+ rv = SECFailure;
+ break;
+ }
+ rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
+ } while ( (SECSuccess == rv) && (group.len) );
+ /* we should be at the end of the set by now */
+ /* save the entries where requested */
+ memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
+
+ return rv;
+}
+
+static SECStatus DecodeExplicit(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem subItem;
+ SECItem constructed = *src;
+
+ rv = GetItem(&constructed, &subItem, PR_FALSE);
+
+ if (SECSuccess == rv)
+ {
+ if (templateEntry->kind & SEC_ASN1_POINTER)
+ {
+ rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
+ }
+ else
+ {
+ rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
+ }
+ }
+
+ return rv;
+}
+
+/* new decoder implementation. This is a recursive function */
+
+static SECStatus DecodeItem(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+ SECStatus rv = SECSuccess;
+ SECItem temp;
+ SECItem mark;
+ PRBool pop = PR_FALSE;
+ PRBool decode = PR_TRUE;
+ PRBool save = PR_FALSE;
+ unsigned long kind;
+ PRBool match = PR_TRUE;
+ PRBool optional = PR_FALSE;
+
+ PR_ASSERT(src && dest && templateEntry && arena);
+#if 0
+ if (!src || !dest || !templateEntry || !arena)
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+#endif
+
+ if (SECSuccess == rv)
+ {
+ /* do the template validation */
+ kind = templateEntry->kind;
+ optional = (0 != (kind & SEC_ASN1_OPTIONAL));
+ if (!kind)
+ {
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ rv = SECFailure;
+ }
+ }
+
+ if (SECSuccess == rv)
+ {
+#ifdef DEBUG
+ if (kind & SEC_ASN1_DEBUG_BREAK)
+ {
+ /* when debugging the decoder or a template that fails to
+ decode, put SEC_ASN1_DEBUG in the component that gives you
+ trouble. The decoder will then get to this block and assert.
+ If you want to debug the rest of the code, you can set a
+ breakpoint and set dontassert to PR_TRUE, which will let
+ you skip over the assert and continue the debugging session
+ past it. */
+ PRBool dontassert = PR_FALSE;
+ PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
+ }
+#endif
+
+ if ((kind & SEC_ASN1_SKIP) ||
+ (kind & SEC_ASN1_SAVE))
+ {
+ /* if skipping or saving this component, don't decode it */
+ decode = PR_FALSE;
+ }
+
+ if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
+ {
+ /* if saving this component, or if it is optional, we may not want to
+ move past it, so save the position in case we have to rewind */
+ mark = *src;
+ if (kind & SEC_ASN1_SAVE)
+ {
+ save = PR_TRUE;
+ if (0 == (kind & SEC_ASN1_SKIP))
+ {
+ /* we will for sure have to rewind when saving this
+ component and not skipping it. This is true for all
+ legacy uses of SEC_ASN1_SAVE where the following entry
+ in the template would causes the same component to be
+ processed again */
+ pop = PR_TRUE;
+ }
+ }
+ }
+
+ rv = GetItem(src, &temp, PR_TRUE);
+ }
+
+ if (SECSuccess == rv)
+ {
+ /* now check if the component matches what we expect in the template */
+
+ if (PR_TRUE == checkTag)
+
+ {
+ rv = MatchComponentType(templateEntry, &temp, &match, dest);
+ }
+
+ if ( (SECSuccess == rv) && (PR_TRUE != match) )
+ {
+ if (kind & SEC_ASN1_OPTIONAL)
+ {
+
+ /* the optional component is missing. This is not fatal. */
+ /* Rewind, don't decode, and don't save */
+ pop = PR_TRUE;
+ decode = PR_FALSE;
+ save = PR_FALSE;
+ }
+ else
+ {
+ /* a required component is missing. abort */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ }
+ }
+ }
+
+ if ((SECSuccess == rv) && (PR_TRUE == decode))
+ {
+ /* the order of processing here is is the tricky part */
+ /* we start with our special cases */
+ /* first, check the component class */
+ if (kind & SEC_ASN1_INLINE)
+ {
+ /* decode inline template */
+ rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
+ }
+
+ else
+ if (kind & SEC_ASN1_EXPLICIT)
+ {
+ rv = DecodeExplicit(dest, templateEntry, &temp, arena);
+ }
+ else
+ if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
+
+ (!(kind & SEC_ASN1_EXPLICIT)))
+ {
+
+ /* decode implicitly tagged components */
+ rv = DecodeImplicit(dest, templateEntry, &temp , arena);
+ }
+ else
+ if (kind & SEC_ASN1_POINTER)
+ {
+ rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
+ }
+ else
+ if (kind & SEC_ASN1_CHOICE)
+ {
+ rv = DecodeChoice(dest, templateEntry, &temp, arena);
+ }
+ else
+ if (kind & SEC_ASN1_ANY)
+ {
+ /* catch-all ANY type, don't decode */
+ save = PR_TRUE;
+ if (kind & SEC_ASN1_INNER)
+ {
+ /* skip the tag and length */
+ SECItem newtemp = temp;
+ rv = GetItem(&newtemp, &temp, PR_FALSE);
+ }
+ }
+ else
+ if (kind & SEC_ASN1_GROUP)
+ {
+ if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
+ (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
+ {
+ rv = DecodeGroup(dest, templateEntry, &temp , arena);
+ }
+ else
+ {
+ /* a group can only be a SET OF or SEQUENCE OF */
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ rv = SECFailure;
+ }
+ }
+ else
+ if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
+ {
+ /* plain SEQUENCE */
+ rv = DecodeSequence(dest, templateEntry, &temp , arena);
+ }
+ else
+ {
+ /* handle all other types as "save" */
+ /* we should only get here for primitive universal types */
+ SECItem newtemp = temp;
+ rv = GetItem(&newtemp, &temp, PR_FALSE);
+ save = PR_TRUE;
+ if ((SECSuccess == rv) &&
+ SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
+ {
+ unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
+ if ( temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
+ tagnum == SEC_ASN1_INTEGER ||
+ tagnum == SEC_ASN1_BIT_STRING ||
+ tagnum == SEC_ASN1_OBJECT_ID ||
+ tagnum == SEC_ASN1_ENUMERATED ||
+ tagnum == SEC_ASN1_UTC_TIME ||
+ tagnum == SEC_ASN1_GENERALIZED_TIME) )
+ {
+ /* these types MUST have at least one content octet */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ }
+ else
+ switch (tagnum)
+ {
+ /* special cases of primitive types */
+ case SEC_ASN1_INTEGER:
+ {
+ /* remove leading zeroes if the caller requested
+ siUnsignedInteger
+ This is to allow RSA key operations to work */
+ SECItem* destItem = (SECItem*) ((char*)dest +
+ templateEntry->offset);
+ if (destItem && (siUnsignedInteger == destItem->type))
+ {
+ while (temp.len > 1 && temp.data[0] == 0)
+ { /* leading 0 */
+ temp.data++;
+ temp.len--;
+ }
+ }
+ break;
+ }
+
+ case SEC_ASN1_BIT_STRING:
+ {
+ /* change the length in the SECItem to be the number
+ of bits */
+ temp.len = (temp.len-1)*8 - (temp.data[0] & 0x7);
+ temp.data++;
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if ((SECSuccess == rv) && (PR_TRUE == save))
+ {
+ SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
+ if (destItem)
+ {
+ /* we leave the type alone in the destination SECItem.
+ If part of the destination was allocated by the decoder, in
+ cases of POINTER, SET OF and SEQUENCE OF, then type is set to
+ siBuffer due to the use of PORT_ArenaZAlloc*/
+ destItem->data = temp.len ? temp.data : NULL;
+ destItem->len = temp.len;
+ }
+ else
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+ }
+
+ if (PR_TRUE == pop)
+ {
+ /* we don't want to move ahead, so restore the position */
+ *src = mark;
+ }
+ return rv;
+}
+
+/* the function below is the public one */
+
+SECStatus SEC_QuickDERDecodeItem(PRArenaPool* arena, void* dest,
+ const SEC_ASN1Template* templateEntry,
+ const SECItem* src)
+{
+ SECStatus rv = SECSuccess;
+ SECItem newsrc;
+
+ if (!arena || !templateEntry || !src)
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+
+ if (SECSuccess == rv)
+ {
+ newsrc = *src;
+ rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
+ if (SECSuccess == rv && newsrc.len)
+ {
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_EXTRA_INPUT);
+ }
+ }
+
+ return rv;
+}
+
diff --git a/lib/util/secalgid.c b/lib/util/secalgid.c
new file mode 100644
index 000000000..d7a1259d7
--- /dev/null
+++ b/lib/util/secalgid.c
@@ -0,0 +1,127 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secoid.h"
+#include "secder.h" /* XXX remove this when remove the DERTemplate */
+#include "secasn1.h"
+#include "secitem.h"
+#include "secerr.h"
+
+SECOidTag
+SECOID_GetAlgorithmTag(SECAlgorithmID *id)
+{
+ if (id == NULL || id->algorithm.data == NULL)
+ return SEC_OID_UNKNOWN;
+
+ return SECOID_FindOIDTag (&(id->algorithm));
+}
+
+SECStatus
+SECOID_SetAlgorithmID(PRArenaPool *arena, SECAlgorithmID *id, SECOidTag which,
+ SECItem *params)
+{
+ SECOidData *oiddata;
+ PRBool add_null_param;
+
+ oiddata = SECOID_FindOIDByTag(which);
+ if ( !oiddata ) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return SECFailure;
+ }
+
+ if (SECITEM_CopyItem(arena, &id->algorithm, &oiddata->oid))
+ return SECFailure;
+
+ switch (which) {
+ case SEC_OID_MD2:
+ case SEC_OID_MD4:
+ case SEC_OID_MD5:
+ case SEC_OID_SHA1:
+ case SEC_OID_SHA224:
+ case SEC_OID_SHA256:
+ case SEC_OID_SHA384:
+ case SEC_OID_SHA512:
+ case SEC_OID_PKCS1_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
+ add_null_param = PR_TRUE;
+ break;
+ default:
+ add_null_param = PR_FALSE;
+ break;
+ }
+
+ if (params) {
+ /*
+ * I am specifically *not* enforcing the following assertion
+ * (by following it up with an error and a return of failure)
+ * because I do not want to introduce any change in the current
+ * behavior. But I do want for us to notice if the following is
+ * ever true, because I do not think it should be so and probably
+ * signifies an error/bug somewhere.
+ */
+ PORT_Assert(!add_null_param || (params->len == 2
+ && params->data[0] == SEC_ASN1_NULL
+ && params->data[1] == 0));
+ if (SECITEM_CopyItem(arena, &id->parameters, params)) {
+ return SECFailure;
+ }
+ } else {
+ /*
+ * Again, this is not considered an error. But if we assume
+ * that nobody tries to set the parameters field themselves
+ * (but always uses this routine to do that), then we should
+ * not hit the following assertion. Unless they forgot to zero
+ * the structure, which could also be a bad (and wrong) thing.
+ */
+ PORT_Assert(id->parameters.data == NULL);
+
+ if (add_null_param) {
+ (void) SECITEM_AllocItem(arena, &id->parameters, 2);
+ if (id->parameters.data == NULL) {
+ return SECFailure;
+ }
+ id->parameters.data[0] = SEC_ASN1_NULL;
+ id->parameters.data[1] = 0;
+ }
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+SECOID_CopyAlgorithmID(PRArenaPool *arena, SECAlgorithmID *to, SECAlgorithmID *from)
+{
+ SECStatus rv;
+
+ rv = SECITEM_CopyItem(arena, &to->algorithm, &from->algorithm);
+ if (rv) return rv;
+ rv = SECITEM_CopyItem(arena, &to->parameters, &from->parameters);
+ return rv;
+}
+
+void SECOID_DestroyAlgorithmID(SECAlgorithmID *algid, PRBool freeit)
+{
+ SECITEM_FreeItem(&algid->parameters, PR_FALSE);
+ SECITEM_FreeItem(&algid->algorithm, PR_FALSE);
+ if(freeit == PR_TRUE)
+ PORT_Free(algid);
+}
+
+SECComparison
+SECOID_CompareAlgorithmID(SECAlgorithmID *a, SECAlgorithmID *b)
+{
+ SECComparison rv;
+
+ rv = SECITEM_CompareItem(&a->algorithm, &b->algorithm);
+ if (rv) return rv;
+ rv = SECITEM_CompareItem(&a->parameters, &b->parameters);
+ return rv;
+}
diff --git a/lib/util/secasn1.h b/lib/util/secasn1.h
new file mode 100644
index 000000000..7b3dd0ed5
--- /dev/null
+++ b/lib/util/secasn1.h
@@ -0,0 +1,294 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Support for encoding/decoding of ASN.1 using BER/DER (Basic/Distinguished
+ * Encoding Rules). The routines are found in and used extensively by the
+ * security library, but exported for other use.
+ *
+ * $Id$
+ */
+
+#ifndef _SECASN1_H_
+#define _SECASN1_H_
+
+#include "utilrename.h"
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secasn1t.h"
+
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/*
+ * XXX These function prototypes need full, explanatory comments.
+ */
+
+/*
+** Decoding.
+*/
+
+extern SEC_ASN1DecoderContext *SEC_ASN1DecoderStart(PLArenaPool *pool,
+ void *dest,
+ const SEC_ASN1Template *t);
+
+/* XXX char or unsigned char? */
+extern SECStatus SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
+ const char *buf,
+ unsigned long len);
+
+extern SECStatus SEC_ASN1DecoderFinish(SEC_ASN1DecoderContext *cx);
+
+/* Higher level code detected an error, abort the rest of the processing */
+extern void SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error);
+
+extern void SEC_ASN1DecoderSetFilterProc(SEC_ASN1DecoderContext *cx,
+ SEC_ASN1WriteProc fn,
+ void *arg, PRBool no_store);
+
+extern void SEC_ASN1DecoderClearFilterProc(SEC_ASN1DecoderContext *cx);
+
+extern void SEC_ASN1DecoderSetNotifyProc(SEC_ASN1DecoderContext *cx,
+ SEC_ASN1NotifyProc fn,
+ void *arg);
+
+extern void SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx);
+
+extern SECStatus SEC_ASN1Decode(PLArenaPool *pool, void *dest,
+ const SEC_ASN1Template *t,
+ const char *buf, long len);
+
+/* Both classic ASN.1 and QuickDER have a feature that removes leading zeroes
+ out of SEC_ASN1_INTEGER if the caller sets siUnsignedInteger in the type
+ field of the target SECItem prior to calling the decoder. Otherwise, the
+ type field is ignored and untouched. For SECItem that are dynamically
+ allocated (from POINTER, SET OF, SEQUENCE OF) the decoder sets the type
+ field to siBuffer. */
+
+extern SECStatus SEC_ASN1DecodeItem(PLArenaPool *pool, void *dest,
+ const SEC_ASN1Template *t,
+ const SECItem *src);
+
+extern SECStatus SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
+ const SEC_ASN1Template* templateEntry,
+ const SECItem* src);
+
+/*
+** Encoding.
+*/
+
+extern SEC_ASN1EncoderContext *SEC_ASN1EncoderStart(const void *src,
+ const SEC_ASN1Template *t,
+ SEC_ASN1WriteProc fn,
+ void *output_arg);
+
+/* XXX char or unsigned char? */
+extern SECStatus SEC_ASN1EncoderUpdate(SEC_ASN1EncoderContext *cx,
+ const char *buf,
+ unsigned long len);
+
+extern void SEC_ASN1EncoderFinish(SEC_ASN1EncoderContext *cx);
+
+/* Higher level code detected an error, abort the rest of the processing */
+extern void SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error);
+
+extern void SEC_ASN1EncoderSetNotifyProc(SEC_ASN1EncoderContext *cx,
+ SEC_ASN1NotifyProc fn,
+ void *arg);
+
+extern void SEC_ASN1EncoderClearNotifyProc(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderSetStreaming(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderClearStreaming(SEC_ASN1EncoderContext *cx);
+
+extern void sec_ASN1EncoderSetDER(SEC_ASN1EncoderContext *cx);
+
+extern void sec_ASN1EncoderClearDER(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderSetTakeFromBuf(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderClearTakeFromBuf(SEC_ASN1EncoderContext *cx);
+
+extern SECStatus SEC_ASN1Encode(const void *src, const SEC_ASN1Template *t,
+ SEC_ASN1WriteProc output_proc,
+ void *output_arg);
+
+/*
+ * If both pool and dest are NULL, the caller should free the returned SECItem
+ * with a SECITEM_FreeItem(..., PR_TRUE) call. If pool is NULL but dest is
+ * not NULL, the caller should free the data buffer pointed to by dest with a
+ * SECITEM_FreeItem(dest, PR_FALSE) or PORT_Free(dest->data) call.
+ */
+extern SECItem * SEC_ASN1EncodeItem(PLArenaPool *pool, SECItem *dest,
+ const void *src, const SEC_ASN1Template *t);
+
+extern SECItem * SEC_ASN1EncodeInteger(PLArenaPool *pool,
+ SECItem *dest, long value);
+
+extern SECItem * SEC_ASN1EncodeUnsignedInteger(PLArenaPool *pool,
+ SECItem *dest,
+ unsigned long value);
+
+extern SECStatus SEC_ASN1DecodeInteger(SECItem *src,
+ unsigned long *value);
+
+/*
+** Utilities.
+*/
+
+/*
+ * We have a length that needs to be encoded; how many bytes will the
+ * encoding take?
+ */
+extern int SEC_ASN1LengthLength (unsigned long len);
+
+/* encode the length and return the number of bytes we encoded. Buffer
+ * must be pre allocated */
+extern int SEC_ASN1EncodeLength(unsigned char *buf,int value);
+
+/*
+ * Find the appropriate subtemplate for the given template.
+ * This may involve calling a "chooser" function, or it may just
+ * be right there. In either case, it is expected to *have* a
+ * subtemplate; this is asserted in debug builds (in non-debug
+ * builds, NULL will be returned).
+ *
+ * "thing" is a pointer to the structure being encoded/decoded
+ * "encoding", when true, means that we are in the process of encoding
+ * (as opposed to in the process of decoding)
+ */
+extern const SEC_ASN1Template *
+SEC_ASN1GetSubtemplate (const SEC_ASN1Template *inTemplate, void *thing,
+ PRBool encoding);
+
+/* whether the template is for a primitive type or a choice of
+ * primitive types
+ */
+extern PRBool SEC_ASN1IsTemplateSimple(const SEC_ASN1Template *theTemplate);
+
+/************************************************************************/
+
+/*
+ * Generic Templates
+ * One for each of the simple types, plus a special one for ANY, plus:
+ * - a pointer to each one of those
+ * - a set of each one of those
+ * - a sequence of each one of those
+ *
+ * Note that these are alphabetical (case insensitive); please add new
+ * ones in the appropriate place.
+ */
+
+extern const SEC_ASN1Template SEC_AnyTemplate[];
+extern const SEC_ASN1Template SEC_BitStringTemplate[];
+extern const SEC_ASN1Template SEC_BMPStringTemplate[];
+extern const SEC_ASN1Template SEC_BooleanTemplate[];
+extern const SEC_ASN1Template SEC_EnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_GeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_IA5StringTemplate[];
+extern const SEC_ASN1Template SEC_IntegerTemplate[];
+extern const SEC_ASN1Template SEC_NullTemplate[];
+extern const SEC_ASN1Template SEC_ObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_OctetStringTemplate[];
+extern const SEC_ASN1Template SEC_PrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_T61StringTemplate[];
+extern const SEC_ASN1Template SEC_UniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_UTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_UTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_VisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_PointerToAnyTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBitStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBooleanTemplate[];
+extern const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_PointerToIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToIntegerTemplate[];
+extern const SEC_ASN1Template SEC_PointerToNullTemplate[];
+extern const SEC_ASN1Template SEC_PointerToObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_PointerToOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToT61StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToVisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_SequenceOfAnyTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBitStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBooleanTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfIntegerTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfNullTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfT61StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_SetOfAnyTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBitStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBooleanTemplate[];
+extern const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_SetOfIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfIntegerTemplate[];
+extern const SEC_ASN1Template SEC_SetOfNullTemplate[];
+extern const SEC_ASN1Template SEC_SetOfObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_SetOfOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfT61StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfVisibleStringTemplate[];
+
+/*
+ * Template for skipping a subitem; this only makes sense when decoding.
+ */
+extern const SEC_ASN1Template SEC_SkipTemplate[];
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs. Sigh.
+*/
+SEC_ASN1_CHOOSER_DECLARE(SEC_AnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BMPStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BooleanTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BitStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_GeneralizedTimeTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_IA5StringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_IntegerTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_NullTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_ObjectIDTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_OctetStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UTCTimeTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UTF8StringTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToAnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToOctetStringTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_SetOfAnyTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_EnumeratedTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToEnumeratedTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SequenceOfAnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SequenceOfObjectIDTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SkipTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UniversalStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PrintableStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_T61StringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToGeneralizedTimeTemplate)
+SEC_END_PROTOS
+#endif /* _SECASN1_H_ */
diff --git a/lib/util/secasn1d.c b/lib/util/secasn1d.c
new file mode 100644
index 000000000..9e751df20
--- /dev/null
+++ b/lib/util/secasn1d.c
@@ -0,0 +1,3237 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id$
+ */
+
+/* #define DEBUG_ASN1D_STATES 1 */
+
+#ifdef DEBUG_ASN1D_STATES
+#include <stdio.h>
+#define PR_Assert sec_asn1d_Assert
+#endif
+
+#include "secasn1.h"
+#include "secerr.h"
+
+typedef enum {
+ beforeIdentifier,
+ duringIdentifier,
+ afterIdentifier,
+ beforeLength,
+ duringLength,
+ afterLength,
+ beforeBitString,
+ duringBitString,
+ duringConstructedString,
+ duringGroup,
+ duringLeaf,
+ duringSaveEncoding,
+ duringSequence,
+ afterConstructedString,
+ afterGroup,
+ afterExplicit,
+ afterImplicit,
+ afterInline,
+ afterPointer,
+ afterSaveEncoding,
+ beforeEndOfContents,
+ duringEndOfContents,
+ afterEndOfContents,
+ beforeChoice,
+ duringChoice,
+ afterChoice,
+ notInUse
+} sec_asn1d_parse_place;
+
+#ifdef DEBUG_ASN1D_STATES
+static const char * const place_names[] = {
+ "beforeIdentifier",
+ "duringIdentifier",
+ "afterIdentifier",
+ "beforeLength",
+ "duringLength",
+ "afterLength",
+ "beforeBitString",
+ "duringBitString",
+ "duringConstructedString",
+ "duringGroup",
+ "duringLeaf",
+ "duringSaveEncoding",
+ "duringSequence",
+ "afterConstructedString",
+ "afterGroup",
+ "afterExplicit",
+ "afterImplicit",
+ "afterInline",
+ "afterPointer",
+ "afterSaveEncoding",
+ "beforeEndOfContents",
+ "duringEndOfContents",
+ "afterEndOfContents",
+ "beforeChoice",
+ "duringChoice",
+ "afterChoice",
+ "notInUse"
+};
+
+static const char * const class_names[] = {
+ "UNIVERSAL",
+ "APPLICATION",
+ "CONTEXT_SPECIFIC",
+ "PRIVATE"
+};
+
+static const char * const method_names[] = { "PRIMITIVE", "CONSTRUCTED" };
+
+static const char * const type_names[] = {
+ "END_OF_CONTENTS",
+ "BOOLEAN",
+ "INTEGER",
+ "BIT_STRING",
+ "OCTET_STRING",
+ "NULL",
+ "OBJECT_ID",
+ "OBJECT_DESCRIPTOR",
+ "(type 08)",
+ "REAL",
+ "ENUMERATED",
+ "EMBEDDED",
+ "UTF8_STRING",
+ "(type 0d)",
+ "(type 0e)",
+ "(type 0f)",
+ "SEQUENCE",
+ "SET",
+ "NUMERIC_STRING",
+ "PRINTABLE_STRING",
+ "T61_STRING",
+ "VIDEOTEXT_STRING",
+ "IA5_STRING",
+ "UTC_TIME",
+ "GENERALIZED_TIME",
+ "GRAPHIC_STRING",
+ "VISIBLE_STRING",
+ "GENERAL_STRING",
+ "UNIVERSAL_STRING",
+ "(type 1d)",
+ "BMP_STRING",
+ "HIGH_TAG_VALUE"
+};
+
+static const char * const flag_names[] = { /* flags, right to left */
+ "OPTIONAL",
+ "EXPLICIT",
+ "ANY",
+ "INLINE",
+ "POINTER",
+ "GROUP",
+ "DYNAMIC",
+ "SKIP",
+ "INNER",
+ "SAVE",
+ "", /* decoder ignores "MAY_STREAM", */
+ "SKIP_REST",
+ "CHOICE",
+ "NO_STREAM",
+ "DEBUG_BREAK",
+ "unknown 08",
+ "unknown 10",
+ "unknown 20",
+ "unknown 40",
+ "unknown 80"
+};
+
+static int /* bool */
+formatKind(unsigned long kind, char * buf)
+{
+ int i;
+ unsigned long k = kind & SEC_ASN1_TAGNUM_MASK;
+ unsigned long notag = kind & (SEC_ASN1_CHOICE | SEC_ASN1_POINTER |
+ SEC_ASN1_INLINE | SEC_ASN1_ANY | SEC_ASN1_SAVE);
+
+ buf[0] = 0;
+ if ((kind & SEC_ASN1_CLASS_MASK) != SEC_ASN1_UNIVERSAL) {
+ sprintf(buf, " %s", class_names[(kind & SEC_ASN1_CLASS_MASK) >> 6] );
+ buf += strlen(buf);
+ }
+ if (kind & SEC_ASN1_METHOD_MASK) {
+ sprintf(buf, " %s", method_names[1]);
+ buf += strlen(buf);
+ }
+ if ((kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL) {
+ if (k || !notag) {
+ sprintf(buf, " %s", type_names[k] );
+ if ((k == SEC_ASN1_SET || k == SEC_ASN1_SEQUENCE) &&
+ (kind & SEC_ASN1_GROUP)) {
+ buf += strlen(buf);
+ sprintf(buf, "_OF");
+ }
+ }
+ } else {
+ sprintf(buf, " [%d]", k);
+ }
+ buf += strlen(buf);
+
+ for (k = kind >> 8, i = 0; k; k >>= 1, ++i) {
+ if (k & 1) {
+ sprintf(buf, " %s", flag_names[i]);
+ buf += strlen(buf);
+ }
+ }
+ return notag != 0;
+}
+
+#endif /* DEBUG_ASN1D_STATES */
+
+typedef enum {
+ allDone,
+ decodeError,
+ keepGoing,
+ needBytes
+} sec_asn1d_parse_status;
+
+struct subitem {
+ const void *data;
+ unsigned long len; /* only used for substrings */
+ struct subitem *next;
+};
+
+typedef struct sec_asn1d_state_struct {
+ SEC_ASN1DecoderContext *top;
+ const SEC_ASN1Template *theTemplate;
+ void *dest;
+
+ void *our_mark; /* free on completion */
+
+ struct sec_asn1d_state_struct *parent; /* aka prev */
+ struct sec_asn1d_state_struct *child; /* aka next */
+
+ sec_asn1d_parse_place place;
+
+ /*
+ * XXX explain the next fields as clearly as possible...
+ */
+ unsigned char found_tag_modifiers;
+ unsigned char expect_tag_modifiers;
+ unsigned long check_tag_mask;
+ unsigned long found_tag_number;
+ unsigned long expect_tag_number;
+ unsigned long underlying_kind;
+
+ unsigned long contents_length;
+ unsigned long pending;
+ unsigned long consumed;
+
+ int depth;
+
+ /*
+ * Bit strings have their length adjusted -- the first octet of the
+ * contents contains a value between 0 and 7 which says how many bits
+ * at the end of the octets are not actually part of the bit string;
+ * when parsing bit strings we put that value here because we need it
+ * later, for adjustment of the length (when the whole string is done).
+ */
+ unsigned int bit_string_unused_bits;
+
+ /*
+ * The following are used for indefinite-length constructed strings.
+ */
+ struct subitem *subitems_head;
+ struct subitem *subitems_tail;
+
+ PRPackedBool
+ allocate, /* when true, need to allocate the destination */
+ endofcontents, /* this state ended up parsing end-of-contents octets */
+ explicit, /* we are handling an explicit header */
+ indefinite, /* the current item has indefinite-length encoding */
+ missing, /* an optional field that was not present */
+ optional, /* the template says this field may be omitted */
+ substring; /* this is a substring of a constructed string */
+
+} sec_asn1d_state;
+
+#define IS_HIGH_TAG_NUMBER(n) ((n) == SEC_ASN1_HIGH_TAG_NUMBER)
+#define LAST_TAG_NUMBER_BYTE(b) (((b) & 0x80) == 0)
+#define TAG_NUMBER_BITS 7
+#define TAG_NUMBER_MASK 0x7f
+
+#define LENGTH_IS_SHORT_FORM(b) (((b) & 0x80) == 0)
+#define LONG_FORM_LENGTH(b) ((b) & 0x7f)
+
+#define HIGH_BITS(field,cnt) ((field) >> ((sizeof(field) * 8) - (cnt)))
+
+
+/*
+ * An "outsider" will have an opaque pointer to this, created by calling
+ * SEC_ASN1DecoderStart(). It will be passed back in to all subsequent
+ * calls to SEC_ASN1DecoderUpdate(), and when done it is passed to
+ * SEC_ASN1DecoderFinish().
+ */
+struct sec_DecoderContext_struct {
+ PRArenaPool *our_pool; /* for our internal allocs */
+ PRArenaPool *their_pool; /* for destination structure allocs */
+#ifdef SEC_ASN1D_FREE_ON_ERROR /*
+ * XXX see comment below (by same
+ * ifdef) that explains why this
+ * does not work (need more smarts
+ * in order to free back to mark)
+ */
+ /*
+ * XXX how to make their_mark work in the case where they do NOT
+ * give us a pool pointer?
+ */
+ void *their_mark; /* free on error */
+#endif
+
+ sec_asn1d_state *current;
+ sec_asn1d_parse_status status;
+
+ SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
+ void *notify_arg; /* argument to notify_proc */
+ PRBool during_notify; /* true during call to notify_proc */
+
+ SEC_ASN1WriteProc filter_proc; /* pass field bytes to this */
+ void *filter_arg; /* argument to that function */
+ PRBool filter_only; /* do not allocate/store fields */
+};
+
+
+/*
+ * XXX this is a fairly generic function that may belong elsewhere
+ */
+static void *
+sec_asn1d_alloc (PRArenaPool *poolp, unsigned long len)
+{
+ void *thing;
+
+ if (poolp != NULL) {
+ /*
+ * Allocate from the pool.
+ */
+ thing = PORT_ArenaAlloc (poolp, len);
+ } else {
+ /*
+ * Allocate generically.
+ */
+ thing = PORT_Alloc (len);
+ }
+
+ return thing;
+}
+
+
+/*
+ * XXX this is a fairly generic function that may belong elsewhere
+ */
+static void *
+sec_asn1d_zalloc (PRArenaPool *poolp, unsigned long len)
+{
+ void *thing;
+
+ thing = sec_asn1d_alloc (poolp, len);
+ if (thing != NULL)
+ PORT_Memset (thing, 0, len);
+ return thing;
+}
+
+
+static sec_asn1d_state *
+sec_asn1d_push_state (SEC_ASN1DecoderContext *cx,
+ const SEC_ASN1Template *theTemplate,
+ void *dest, PRBool new_depth)
+{
+ sec_asn1d_state *state, *new_state;
+
+ state = cx->current;
+
+ PORT_Assert (state == NULL || state->child == NULL);
+
+ if (state != NULL) {
+ PORT_Assert (state->our_mark == NULL);
+ state->our_mark = PORT_ArenaMark (cx->our_pool);
+ }
+
+ new_state = (sec_asn1d_state*)sec_asn1d_zalloc (cx->our_pool,
+ sizeof(*new_state));
+ if (new_state == NULL) {
+ goto loser;
+ }
+
+ new_state->top = cx;
+ new_state->parent = state;
+ new_state->theTemplate = theTemplate;
+ new_state->place = notInUse;
+ if (dest != NULL)
+ new_state->dest = (char *)dest + theTemplate->offset;
+
+ if (state != NULL) {
+ new_state->depth = state->depth;
+ if (new_depth) {
+ if (++new_state->depth > SEC_ASN1D_MAX_DEPTH) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ goto loser;
+ }
+ }
+ state->child = new_state;
+ }
+
+ cx->current = new_state;
+ return new_state;
+
+loser:
+ cx->status = decodeError;
+ if (state != NULL) {
+ PORT_ArenaRelease(cx->our_pool, state->our_mark);
+ state->our_mark = NULL;
+ }
+ return NULL;
+}
+
+
+static void
+sec_asn1d_scrub_state (sec_asn1d_state *state)
+{
+ /*
+ * Some default "scrubbing".
+ * XXX right set of initializations?
+ */
+ state->place = beforeIdentifier;
+ state->endofcontents = PR_FALSE;
+ state->indefinite = PR_FALSE;
+ state->missing = PR_FALSE;
+ PORT_Assert (state->consumed == 0);
+}
+
+
+static void
+sec_asn1d_notify_before (SEC_ASN1DecoderContext *cx, void *dest, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_TRUE, dest, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static void
+sec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_FALSE, dest, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static sec_asn1d_state *
+sec_asn1d_init_state_based_on_template (sec_asn1d_state *state)
+{
+ PRBool explicit, optional, universal;
+ unsigned char expect_tag_modifiers;
+ unsigned long encode_kind, under_kind;
+ unsigned long check_tag_mask, expect_tag_number;
+
+
+ /* XXX Check that both of these tests are really needed/appropriate. */
+ if (state == NULL || state->top->status == decodeError)
+ return state;
+
+ encode_kind = state->theTemplate->kind;
+
+ if (encode_kind & SEC_ASN1_SAVE) {
+ /*
+ * This is a "magic" field that saves away all bytes, allowing
+ * the immediately following field to still be decoded from this
+ * same spot -- sort of a fork.
+ */
+ /* check that there are no extraneous bits */
+ PORT_Assert (encode_kind == SEC_ASN1_SAVE);
+ if (state->top->filter_only) {
+ /*
+ * If we are not storing, then we do not do the SAVE field
+ * at all. Just move ahead to the "real" field instead,
+ * doing the appropriate notify calls before and after.
+ */
+ sec_asn1d_notify_after (state->top, state->dest, state->depth);
+ /*
+ * Since we are not storing, allow for our current dest value
+ * to be NULL. (This might not actually occur, but right now I
+ * cannot convince myself one way or the other.) If it is NULL,
+ * assume that our parent dest can help us out.
+ */
+ if (state->dest == NULL)
+ state->dest = state->parent->dest;
+ else
+ state->dest = (char *)state->dest - state->theTemplate->offset;
+ state->theTemplate++;
+ if (state->dest != NULL)
+ state->dest = (char *)state->dest + state->theTemplate->offset;
+ sec_asn1d_notify_before (state->top, state->dest, state->depth);
+ encode_kind = state->theTemplate->kind;
+ PORT_Assert ((encode_kind & SEC_ASN1_SAVE) == 0);
+ } else {
+ sec_asn1d_scrub_state (state);
+ state->place = duringSaveEncoding;
+ state = sec_asn1d_push_state (state->top, SEC_AnyTemplate,
+ state->dest, PR_FALSE);
+ if (state != NULL)
+ state = sec_asn1d_init_state_based_on_template (state);
+ return state;
+ }
+ }
+
+
+ universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+ optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+ PORT_Assert (!(explicit && universal)); /* bad templates */
+
+ encode_kind &= ~SEC_ASN1_DYNAMIC;
+ encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+ if (encode_kind & SEC_ASN1_CHOICE) {
+#if 0 /* XXX remove? */
+ sec_asn1d_state *child = sec_asn1d_push_state(state->top, state->theTemplate, state->dest, PR_FALSE);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ child->allocate = state->allocate;
+ child->place = beforeChoice;
+ return child;
+#else
+ state->place = beforeChoice;
+ return state;
+#endif
+ }
+
+ if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
+ && !explicit)) {
+ const SEC_ASN1Template *subt;
+ void *dest;
+ PRBool child_allocate;
+
+ PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
+
+ sec_asn1d_scrub_state (state);
+ child_allocate = PR_FALSE;
+
+ if (encode_kind & SEC_ASN1_POINTER) {
+ /*
+ * A POINTER means we need to allocate the destination for
+ * this field. But, since it may also be an optional field,
+ * we defer the allocation until later; we just record that
+ * it needs to be done.
+ *
+ * There are two possible scenarios here -- one is just a
+ * plain POINTER (kind of like INLINE, except with allocation)
+ * and the other is an implicitly-tagged POINTER. We don't
+ * need to do anything special here for the two cases, but
+ * since the template definition can be tricky, we do check
+ * that there are no extraneous bits set in encode_kind.
+ *
+ * XXX The same conditions which assert should set an error.
+ */
+ if (universal) {
+ /*
+ * "universal" means this entry is a standalone POINTER;
+ * there should be no other bits set in encode_kind.
+ */
+ PORT_Assert (encode_kind == SEC_ASN1_POINTER);
+ } else {
+ /*
+ * If we get here we have an implicitly-tagged field
+ * that needs to be put into a POINTER. The subtemplate
+ * will determine how to decode the field, but encode_kind
+ * describes the (implicit) tag we are looking for.
+ * The non-tag bits of encode_kind will be ignored by
+ * the code below; none of them should be set, however,
+ * except for the POINTER bit itself -- so check that.
+ */
+ PORT_Assert ((encode_kind & ~SEC_ASN1_TAG_MASK)
+ == SEC_ASN1_POINTER);
+ }
+ if (!state->top->filter_only)
+ child_allocate = PR_TRUE;
+ dest = NULL;
+ state->place = afterPointer;
+ } else {
+ dest = state->dest;
+ if (encode_kind & SEC_ASN1_INLINE) {
+ /* check that there are no extraneous bits */
+ PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
+ state->place = afterInline;
+ } else {
+ state->place = afterImplicit;
+ }
+ }
+
+ state->optional = optional;
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest, PR_FALSE);
+ state = sec_asn1d_push_state (state->top, subt, dest, PR_FALSE);
+ if (state == NULL)
+ return NULL;
+
+ state->allocate = child_allocate;
+
+ if (universal) {
+ state = sec_asn1d_init_state_based_on_template (state);
+ if (state != NULL) {
+ /*
+ * If this field is optional, we need to record that on
+ * the pushed child so it won't fail if the field isn't
+ * found. I can't think of a way that this new state
+ * could already have optional set (which we would wipe
+ * out below if our local optional is not set) -- but
+ * just to be sure, assert that it isn't set.
+ */
+ PORT_Assert (!state->optional);
+ state->optional = optional;
+ }
+ return state;
+ }
+
+ under_kind = state->theTemplate->kind;
+ under_kind &= ~SEC_ASN1_MAY_STREAM;
+ } else if (explicit) {
+ /*
+ * For explicit, we only need to match the encoding tag next,
+ * then we will push another state to handle the entire inner
+ * part. In this case, there is no underlying kind which plays
+ * any part in the determination of the outer, explicit tag.
+ * So we just set under_kind to 0, which is not a valid tag,
+ * and the rest of the tag matching stuff should be okay.
+ */
+ under_kind = 0;
+ } else {
+ /*
+ * Nothing special; the underlying kind and the given encoding
+ * information are the same.
+ */
+ under_kind = encode_kind;
+ }
+
+ /* XXX is this the right set of bits to test here? */
+ PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
+ | SEC_ASN1_MAY_STREAM
+ | SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);
+
+ if (encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) {
+ PORT_Assert (encode_kind == under_kind);
+ if (encode_kind & SEC_ASN1_SKIP) {
+ PORT_Assert (!optional);
+ PORT_Assert (encode_kind == SEC_ASN1_SKIP);
+ state->dest = NULL;
+ }
+ check_tag_mask = 0;
+ expect_tag_modifiers = 0;
+ expect_tag_number = 0;
+ } else {
+ check_tag_mask = SEC_ASN1_TAG_MASK;
+ expect_tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK
+ & ~SEC_ASN1_TAGNUM_MASK;
+ /*
+ * XXX This assumes only single-octet identifiers. To handle
+ * the HIGH TAG form we would need to do some more work, especially
+ * in how to specify them in the template, because right now we
+ * do not provide a way to specify more *tag* bits in encode_kind.
+ */
+ expect_tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
+
+ switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
+ case SEC_ASN1_SET:
+ /*
+ * XXX A plain old SET (as opposed to a SET OF) is not implemented.
+ * If it ever is, remove this assert...
+ */
+ PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
+ /* fallthru */
+ case SEC_ASN1_SEQUENCE:
+ expect_tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+ break;
+ case SEC_ASN1_BIT_STRING:
+ case SEC_ASN1_BMP_STRING:
+ case SEC_ASN1_GENERALIZED_TIME:
+ case SEC_ASN1_IA5_STRING:
+ case SEC_ASN1_OCTET_STRING:
+ case SEC_ASN1_PRINTABLE_STRING:
+ case SEC_ASN1_T61_STRING:
+ case SEC_ASN1_UNIVERSAL_STRING:
+ case SEC_ASN1_UTC_TIME:
+ case SEC_ASN1_UTF8_STRING:
+ case SEC_ASN1_VISIBLE_STRING:
+ check_tag_mask &= ~SEC_ASN1_CONSTRUCTED;
+ break;
+ }
+ }
+
+ state->check_tag_mask = check_tag_mask;
+ state->expect_tag_modifiers = expect_tag_modifiers;
+ state->expect_tag_number = expect_tag_number;
+ state->underlying_kind = under_kind;
+ state->explicit = explicit;
+ state->optional = optional;
+
+ sec_asn1d_scrub_state (state);
+
+ return state;
+}
+
+static sec_asn1d_state *
+sec_asn1d_get_enclosing_construct(sec_asn1d_state *state)
+{
+ for (state = state->parent; state; state = state->parent) {
+ sec_asn1d_parse_place place = state->place;
+ if (place != afterImplicit &&
+ place != afterPointer &&
+ place != afterInline &&
+ place != afterSaveEncoding &&
+ place != duringSaveEncoding &&
+ place != duringChoice) {
+
+ /* we've walked up the stack to a state that represents
+ ** the enclosing construct.
+ */
+ break;
+ }
+ }
+ return state;
+}
+
+static PRBool
+sec_asn1d_parent_allows_EOC(sec_asn1d_state *state)
+{
+ /* get state of enclosing construct. */
+ state = sec_asn1d_get_enclosing_construct(state);
+ if (state) {
+ sec_asn1d_parse_place place = state->place;
+ /* Is it one of the types that permits an unexpected EOC? */
+ int eoc_permitted =
+ (place == duringGroup ||
+ place == duringConstructedString ||
+ state->child->optional);
+ return (state->indefinite && eoc_permitted) ? PR_TRUE : PR_FALSE;
+ }
+ return PR_FALSE;
+}
+
+static unsigned long
+sec_asn1d_parse_identifier (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+ unsigned char tag_number;
+
+ PORT_Assert (state->place == beforeIdentifier);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ byte = (unsigned char) *buf;
+#ifdef DEBUG_ASN1D_STATES
+ {
+ char kindBuf[256];
+ formatKind(byte, kindBuf);
+ printf("Found tag %02x %s\n", byte, kindBuf);
+ }
+#endif
+ tag_number = byte & SEC_ASN1_TAGNUM_MASK;
+
+ if (IS_HIGH_TAG_NUMBER (tag_number)) {
+ state->place = duringIdentifier;
+ state->found_tag_number = 0;
+ /*
+ * Actually, we have no idea how many bytes are pending, but we
+ * do know that it is at least 1. That is all we know; we have
+ * to look at each byte to know if there is another, etc.
+ */
+ state->pending = 1;
+ } else {
+ if (byte == 0 && sec_asn1d_parent_allows_EOC(state)) {
+ /*
+ * Our parent has indefinite-length encoding, and the
+ * entire tag found is 0, so it seems that we have hit the
+ * end-of-contents octets. To handle this, we just change
+ * our state to that which expects to get the bytes of the
+ * end-of-contents octets and let that code re-read this byte
+ * so that our categorization of field types is correct.
+ * After that, our parent will then deal with everything else.
+ */
+ state->place = duringEndOfContents;
+ state->pending = 2;
+ state->found_tag_number = 0;
+ state->found_tag_modifiers = 0;
+ /*
+ * We might be an optional field that is, as we now find out,
+ * missing. Give our parent a clue that this happened.
+ */
+ if (state->optional)
+ state->missing = PR_TRUE;
+ return 0;
+ }
+ state->place = afterIdentifier;
+ state->found_tag_number = tag_number;
+ }
+ state->found_tag_modifiers = byte & ~SEC_ASN1_TAGNUM_MASK;
+
+ return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_identifier (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+ int count;
+
+ PORT_Assert (state->pending == 1);
+ PORT_Assert (state->place == duringIdentifier);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ count = 0;
+
+ while (len && state->pending) {
+ if (HIGH_BITS (state->found_tag_number, TAG_NUMBER_BITS) != 0) {
+ /*
+ * The given high tag number overflows our container;
+ * just give up. This is not likely to *ever* happen.
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+
+ state->found_tag_number <<= TAG_NUMBER_BITS;
+
+ byte = (unsigned char) buf[count++];
+ state->found_tag_number |= (byte & TAG_NUMBER_MASK);
+
+ len--;
+ if (LAST_TAG_NUMBER_BYTE (byte))
+ state->pending = 0;
+ }
+
+ if (state->pending == 0)
+ state->place = afterIdentifier;
+
+ return count;
+}
+
+
+static void
+sec_asn1d_confirm_identifier (sec_asn1d_state *state)
+{
+ PRBool match;
+
+ PORT_Assert (state->place == afterIdentifier);
+
+ match = (PRBool)(((state->found_tag_modifiers & state->check_tag_mask)
+ == state->expect_tag_modifiers)
+ && ((state->found_tag_number & state->check_tag_mask)
+ == state->expect_tag_number));
+ if (match) {
+ state->place = beforeLength;
+ } else {
+ if (state->optional) {
+ state->missing = PR_TRUE;
+ state->place = afterEndOfContents;
+ } else {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ }
+ }
+}
+
+
+static unsigned long
+sec_asn1d_parse_length (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+
+ PORT_Assert (state->place == beforeLength);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ /*
+ * The default/likely outcome. It may get adjusted below.
+ */
+ state->place = afterLength;
+
+ byte = (unsigned char) *buf;
+
+ if (LENGTH_IS_SHORT_FORM (byte)) {
+ state->contents_length = byte;
+ } else {
+ state->contents_length = 0;
+ state->pending = LONG_FORM_LENGTH (byte);
+ if (state->pending == 0) {
+ state->indefinite = PR_TRUE;
+ } else {
+ state->place = duringLength;
+ }
+ }
+
+ /* If we're parsing an ANY, SKIP, or SAVE template, and
+ ** the object being saved is definite length encoded and constructed,
+ ** there's no point in decoding that construct's members.
+ ** So, just forget it's constructed and treat it as primitive.
+ ** (SAVE appears as an ANY at this point)
+ */
+ if (!state->indefinite &&
+ (state->underlying_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP))) {
+ state->found_tag_modifiers &= ~SEC_ASN1_CONSTRUCTED;
+ }
+
+ return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_length (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ int count;
+
+ PORT_Assert (state->pending > 0);
+ PORT_Assert (state->place == duringLength);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ count = 0;
+
+ while (len && state->pending) {
+ if (HIGH_BITS (state->contents_length, 9) != 0) {
+ /*
+ * The given full content length overflows our container;
+ * just give up.
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+
+ state->contents_length <<= 8;
+ state->contents_length |= (unsigned char) buf[count++];
+
+ len--;
+ state->pending--;
+ }
+
+ if (state->pending == 0)
+ state->place = afterLength;
+
+ return count;
+}
+
+
+static void
+sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
+{
+ SECItem *item;
+ PRArenaPool *poolp;
+ unsigned long alloc_len;
+
+#ifdef DEBUG_ASN1D_STATES
+ {
+ printf("Found Length %d %s\n", state->contents_length,
+ state->indefinite ? "indefinite" : "");
+ }
+#endif
+
+ /*
+ * XXX I cannot decide if this allocation should exclude the case
+ * where state->endofcontents is true -- figure it out!
+ */
+ if (state->allocate) {
+ void *dest;
+
+ PORT_Assert (state->dest == NULL);
+ /*
+ * We are handling a POINTER or a member of a GROUP, and need to
+ * allocate for the data structure.
+ */
+ dest = sec_asn1d_zalloc (state->top->their_pool,
+ state->theTemplate->size);
+ if (dest == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+ state->dest = (char *)dest + state->theTemplate->offset;
+
+ /*
+ * For a member of a GROUP, our parent will later put the
+ * pointer wherever it belongs. But for a POINTER, we need
+ * to record the destination now, in case notify or filter
+ * procs need access to it -- they cannot find it otherwise,
+ * until it is too late (for one-pass processing).
+ */
+ if (state->parent->place == afterPointer) {
+ void **placep;
+
+ placep = state->parent->dest;
+ *placep = dest;
+ }
+ }
+
+ /*
+ * Remember, length may be indefinite here! In that case,
+ * both contents_length and pending will be zero.
+ */
+ state->pending = state->contents_length;
+
+ /* If this item has definite length encoding, and
+ ** is enclosed by a definite length constructed type,
+ ** make sure it isn't longer than the remaining space in that
+ ** constructed type.
+ */
+ if (state->contents_length > 0) {
+ sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state);
+ if (parent && !parent->indefinite &&
+ state->consumed + state->contents_length > parent->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ }
+
+ /*
+ * An EXPLICIT is nothing but an outer header, which we have
+ * already parsed and accepted. Now we need to do the inner
+ * header and its contents.
+ */
+ if (state->explicit) {
+ state->place = afterExplicit;
+ state = sec_asn1d_push_state (state->top,
+ SEC_ASN1GetSubtemplate(state->theTemplate,
+ state->dest,
+ PR_FALSE),
+ state->dest, PR_TRUE);
+ if (state != NULL)
+ state = sec_asn1d_init_state_based_on_template (state);
+ return;
+ }
+
+ /*
+ * For GROUP (SET OF, SEQUENCE OF), even if we know the length here
+ * we cannot tell how many items we will end up with ... so push a
+ * state that can keep track of "children" (the individual members
+ * of the group; we will allocate as we go and put them all together
+ * at the end.
+ */
+ if (state->underlying_kind & SEC_ASN1_GROUP) {
+ /* XXX If this assertion holds (should be able to confirm it via
+ * inspection, too) then move this code into the switch statement
+ * below under cases SET_OF and SEQUENCE_OF; it will be cleaner.
+ */
+ PORT_Assert (state->underlying_kind == SEC_ASN1_SET_OF
+ || state->underlying_kind == SEC_ASN1_SEQUENCE_OF
+ || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
+ || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
+ );
+ if (state->contents_length != 0 || state->indefinite) {
+ const SEC_ASN1Template *subt;
+
+ state->place = duringGroup;
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest,
+ PR_FALSE);
+ state = sec_asn1d_push_state (state->top, subt, NULL, PR_TRUE);
+ if (state != NULL) {
+ if (!state->top->filter_only)
+ state->allocate = PR_TRUE; /* XXX propogate this? */
+ /*
+ * Do the "before" field notification for next in group.
+ */
+ sec_asn1d_notify_before (state->top, state->dest, state->depth);
+ state = sec_asn1d_init_state_based_on_template (state);
+ }
+ } else {
+ /*
+ * A group of zero; we are done.
+ * Set state to afterGroup and let that code plant the NULL.
+ */
+ state->place = afterGroup;
+ }
+ return;
+ }
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_SEQUENCE:
+ /*
+ * We need to push a child to handle the individual fields.
+ */
+ state->place = duringSequence;
+ state = sec_asn1d_push_state (state->top, state->theTemplate + 1,
+ state->dest, PR_TRUE);
+ if (state != NULL) {
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1d_notify_before (state->top, state->dest, state->depth);
+ state = sec_asn1d_init_state_based_on_template (state);
+ }
+ break;
+
+ case SEC_ASN1_SET: /* XXX SET is not really implemented */
+ /*
+ * XXX A plain SET requires special handling; scanning of a
+ * template to see where a field should go (because by definition,
+ * they are not in any particular order, and you have to look at
+ * each tag to disambiguate what the field is). We may never
+ * implement this because in practice, it seems to be unused.
+ */
+ PORT_Assert(0);
+ PORT_SetError (SEC_ERROR_BAD_DER); /* XXX */
+ state->top->status = decodeError;
+ break;
+
+ case SEC_ASN1_NULL:
+ /*
+ * The NULL type, by definition, is "nothing", content length of zero.
+ * An indefinite-length encoding is not alloweed.
+ */
+ if (state->contents_length || state->indefinite) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ break;
+ }
+ if (state->dest != NULL) {
+ item = (SECItem *)(state->dest);
+ item->data = NULL;
+ item->len = 0;
+ }
+ state->place = afterEndOfContents;
+ break;
+
+ case SEC_ASN1_BMP_STRING:
+ /* Error if length is not divisable by 2 */
+ if (state->contents_length % 2) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ break;
+ }
+ /* otherwise, handle as other string types */
+ goto regular_string_type;
+
+ case SEC_ASN1_UNIVERSAL_STRING:
+ /* Error if length is not divisable by 4 */
+ if (state->contents_length % 4) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ break;
+ }
+ /* otherwise, handle as other string types */
+ goto regular_string_type;
+
+ case SEC_ASN1_SKIP:
+ case SEC_ASN1_ANY:
+ case SEC_ASN1_ANY_CONTENTS:
+ /*
+ * These are not (necessarily) strings, but they need nearly
+ * identical handling (especially when we need to deal with
+ * constructed sub-pieces), so we pretend they are.
+ */
+ /* fallthru */
+regular_string_type:
+ case SEC_ASN1_BIT_STRING:
+ case SEC_ASN1_IA5_STRING:
+ case SEC_ASN1_OCTET_STRING:
+ case SEC_ASN1_PRINTABLE_STRING:
+ case SEC_ASN1_T61_STRING:
+ case SEC_ASN1_UTC_TIME:
+ case SEC_ASN1_UTF8_STRING:
+ case SEC_ASN1_VISIBLE_STRING:
+ /*
+ * We are allocating for a primitive or a constructed string.
+ * If it is a constructed string, it may also be indefinite-length.
+ * If it is primitive, the length can (legally) be zero.
+ * Our first order of business is to allocate the memory for
+ * the string, if we can (if we know the length).
+ */
+ item = (SECItem *)(state->dest);
+
+ /*
+ * If the item is a definite-length constructed string, then
+ * the contents_length is actually larger than what we need
+ * (because it also counts each intermediate header which we
+ * will be throwing away as we go), but it is a perfectly good
+ * upper bound that we just allocate anyway, and then concat
+ * as we go; we end up wasting a few extra bytes but save a
+ * whole other copy.
+ */
+ alloc_len = state->contents_length;
+ poolp = NULL; /* quiet compiler warnings about unused... */
+
+ if (item == NULL || state->top->filter_only) {
+ if (item != NULL) {
+ item->data = NULL;
+ item->len = 0;
+ }
+ alloc_len = 0;
+ } else if (state->substring) {
+ /*
+ * If we are a substring of a constructed string, then we may
+ * not have to allocate anything (because our parent, the
+ * actual constructed string, did it for us). If we are a
+ * substring and we *do* have to allocate, that means our
+ * parent is an indefinite-length, so we allocate from our pool;
+ * later our parent will copy our string into the aggregated
+ * whole and free our pool allocation.
+ */
+ if (item->data == NULL) {
+ PORT_Assert (item->len == 0);
+ poolp = state->top->our_pool;
+ } else {
+ alloc_len = 0;
+ }
+ } else {
+ item->len = 0;
+ item->data = NULL;
+ poolp = state->top->their_pool;
+ }
+
+ if (alloc_len || ((! state->indefinite)
+ && (state->subitems_head != NULL))) {
+ struct subitem *subitem;
+ int len;
+
+ PORT_Assert (item);
+ if (!item) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ PORT_Assert (item->len == 0 && item->data == NULL);
+ /*
+ * Check for and handle an ANY which has stashed aside the
+ * header (identifier and length) bytes for us to include
+ * in the saved contents.
+ */
+ if (state->subitems_head != NULL) {
+ PORT_Assert (state->underlying_kind == SEC_ASN1_ANY);
+ for (subitem = state->subitems_head;
+ subitem != NULL; subitem = subitem->next)
+ alloc_len += subitem->len;
+ }
+
+ item->data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len);
+ if (item->data == NULL) {
+ state->top->status = decodeError;
+ break;
+ }
+
+ len = 0;
+ for (subitem = state->subitems_head;
+ subitem != NULL; subitem = subitem->next) {
+ PORT_Memcpy (item->data + len, subitem->data, subitem->len);
+ len += subitem->len;
+ }
+ item->len = len;
+
+ /*
+ * Because we use arenas and have a mark set, we later free
+ * everything we have allocated, so this does *not* present
+ * a memory leak (it is just temporarily left dangling).
+ */
+ state->subitems_head = state->subitems_tail = NULL;
+ }
+
+ if (state->contents_length == 0 && (! state->indefinite)) {
+ /*
+ * A zero-length simple or constructed string; we are done.
+ */
+ state->place = afterEndOfContents;
+ } else if (state->found_tag_modifiers & SEC_ASN1_CONSTRUCTED) {
+ const SEC_ASN1Template *sub;
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_ANY:
+ case SEC_ASN1_ANY_CONTENTS:
+ sub = SEC_AnyTemplate;
+ break;
+ case SEC_ASN1_BIT_STRING:
+ sub = SEC_BitStringTemplate;
+ break;
+ case SEC_ASN1_BMP_STRING:
+ sub = SEC_BMPStringTemplate;
+ break;
+ case SEC_ASN1_GENERALIZED_TIME:
+ sub = SEC_GeneralizedTimeTemplate;
+ break;
+ case SEC_ASN1_IA5_STRING:
+ sub = SEC_IA5StringTemplate;
+ break;
+ case SEC_ASN1_OCTET_STRING:
+ sub = SEC_OctetStringTemplate;
+ break;
+ case SEC_ASN1_PRINTABLE_STRING:
+ sub = SEC_PrintableStringTemplate;
+ break;
+ case SEC_ASN1_T61_STRING:
+ sub = SEC_T61StringTemplate;
+ break;
+ case SEC_ASN1_UNIVERSAL_STRING:
+ sub = SEC_UniversalStringTemplate;
+ break;
+ case SEC_ASN1_UTC_TIME:
+ sub = SEC_UTCTimeTemplate;
+ break;
+ case SEC_ASN1_UTF8_STRING:
+ sub = SEC_UTF8StringTemplate;
+ break;
+ case SEC_ASN1_VISIBLE_STRING:
+ sub = SEC_VisibleStringTemplate;
+ break;
+ case SEC_ASN1_SKIP:
+ sub = SEC_SkipTemplate;
+ break;
+ default: /* redundant given outer switch cases, but */
+ PORT_Assert(0); /* the compiler does not seem to know that, */
+ sub = NULL; /* so just do enough to quiet it. */
+ break;
+ }
+
+ state->place = duringConstructedString;
+ state = sec_asn1d_push_state (state->top, sub, item, PR_TRUE);
+ if (state != NULL) {
+ state->substring = PR_TRUE; /* XXX propogate? */
+ state = sec_asn1d_init_state_based_on_template (state);
+ }
+ } else if (state->indefinite) {
+ /*
+ * An indefinite-length string *must* be constructed!
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ /*
+ * A non-zero-length simple string.
+ */
+ if (state->underlying_kind == SEC_ASN1_BIT_STRING)
+ state->place = beforeBitString;
+ else
+ state->place = duringLeaf;
+ }
+ break;
+
+ default:
+ /*
+ * We are allocating for a simple leaf item.
+ */
+ if (state->contents_length) {
+ if (state->dest != NULL) {
+ item = (SECItem *)(state->dest);
+ item->len = 0;
+ if (state->top->filter_only) {
+ item->data = NULL;
+ } else {
+ item->data = (unsigned char*)
+ sec_asn1d_zalloc (state->top->their_pool,
+ state->contents_length);
+ if (item->data == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+ }
+ }
+ state->place = duringLeaf;
+ } else {
+ /*
+ * An indefinite-length or zero-length item is not allowed.
+ * (All legal cases of such were handled above.)
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ }
+ }
+}
+
+
+static void
+sec_asn1d_free_child (sec_asn1d_state *state, PRBool error)
+{
+ if (state->child != NULL) {
+ PORT_Assert (error || state->child->consumed == 0);
+ PORT_Assert (state->our_mark != NULL);
+ PORT_ArenaZRelease (state->top->our_pool, state->our_mark);
+ if (error && state->top->their_pool == NULL) {
+ /*
+ * XXX We need to free anything allocated.
+ * At this point, we failed in the middle of decoding. But we
+ * can't free the data we previously allocated with PR_Malloc
+ * unless we keep track of every pointer. So instead we have a
+ * memory leak when decoding fails half-way, unless an arena is
+ * used. See bug 95311 .
+ */
+ }
+ state->child = NULL;
+ state->our_mark = NULL;
+ } else {
+ /*
+ * It is important that we do not leave a mark unreleased/unmarked.
+ * But I do not think we should ever have one set in this case, only
+ * if we had a child (handled above). So check for that. If this
+ * assertion should ever get hit, then we probably need to add code
+ * here to release back to our_mark (and then set our_mark to NULL).
+ */
+ PORT_Assert (state->our_mark == NULL);
+ }
+ state->place = beforeEndOfContents;
+}
+
+/* We have just saved an entire encoded ASN.1 object (type) for a SAVE
+** template, and now in the next template, we are going to decode that
+** saved data by calling SEC_ASN1DecoderUpdate recursively.
+** If that recursive call fails with needBytes, it is a fatal error,
+** because the encoded object should have been complete.
+** If that recursive call fails with decodeError, it will have already
+** cleaned up the state stack, so we must bail out quickly.
+**
+** These checks of the status returned by the recursive call are now
+** done in the caller of this function, immediately after it returns.
+*/
+static void
+sec_asn1d_reuse_encoding (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ unsigned long consumed;
+ SECItem *item;
+ void *dest;
+
+
+ child = state->child;
+ PORT_Assert (child != NULL);
+
+ consumed = child->consumed;
+ child->consumed = 0;
+
+ item = (SECItem *)(state->dest);
+ PORT_Assert (item != NULL);
+
+ PORT_Assert (item->len == consumed);
+
+ /*
+ * Free any grandchild.
+ */
+ sec_asn1d_free_child (child, PR_FALSE);
+
+ /*
+ * Notify after the SAVE field.
+ */
+ sec_asn1d_notify_after (state->top, state->dest, state->depth);
+
+ /*
+ * Adjust to get new dest and move forward.
+ */
+ dest = (char *)state->dest - state->theTemplate->offset;
+ state->theTemplate++;
+ child->dest = (char *)dest + state->theTemplate->offset;
+ child->theTemplate = state->theTemplate;
+
+ /*
+ * Notify before the "real" field.
+ */
+ PORT_Assert (state->depth == child->depth);
+ sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+ /*
+ * This will tell DecoderUpdate to return when it is done.
+ */
+ state->place = afterSaveEncoding;
+
+ /*
+ * We already have a child; "push" it by making it current.
+ */
+ state->top->current = child;
+
+ /*
+ * And initialize it so it is ready to parse.
+ */
+ (void) sec_asn1d_init_state_based_on_template(child);
+
+ /*
+ * Now parse that out of our data.
+ */
+ if (SEC_ASN1DecoderUpdate (state->top,
+ (char *) item->data, item->len) != SECSuccess)
+ return;
+ if (state->top->status == needBytes) {
+ return;
+ }
+
+ PORT_Assert (state->top->current == state);
+ PORT_Assert (state->child == child);
+
+ /*
+ * That should have consumed what we consumed before.
+ */
+ PORT_Assert (consumed == child->consumed);
+ child->consumed = 0;
+
+ /*
+ * Done.
+ */
+ state->consumed += consumed;
+ child->place = notInUse;
+ state->place = afterEndOfContents;
+}
+
+
+static unsigned long
+sec_asn1d_parse_leaf (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ SECItem *item;
+ unsigned long bufLen;
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ if (state->pending < len)
+ len = state->pending;
+
+ bufLen = len;
+
+ item = (SECItem *)(state->dest);
+ if (item != NULL && item->data != NULL) {
+ /* Strip leading zeroes when target is unsigned integer */
+ if (state->underlying_kind == SEC_ASN1_INTEGER && /* INTEGER */
+ item->len == 0 && /* MSB */
+ item->type == siUnsignedInteger) /* unsigned */
+ {
+ while (len > 1 && buf[0] == 0) { /* leading 0 */
+ buf++;
+ len--;
+ }
+ }
+ PORT_Memcpy (item->data + item->len, buf, len);
+ item->len += len;
+ }
+ state->pending -= bufLen;
+ if (state->pending == 0)
+ state->place = beforeEndOfContents;
+
+ return bufLen;
+}
+
+
+static unsigned long
+sec_asn1d_parse_bit_string (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+
+ /*PORT_Assert (state->pending > 0); */
+ PORT_Assert (state->place == beforeBitString);
+
+ if (state->pending == 0) {
+ if (state->dest != NULL) {
+ SECItem *item = (SECItem *)(state->dest);
+ item->data = NULL;
+ item->len = 0;
+ state->place = beforeEndOfContents;
+ return 0;
+ }
+ }
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ byte = (unsigned char) *buf;
+ if (byte > 7) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+
+ state->bit_string_unused_bits = byte;
+ state->place = duringBitString;
+ state->pending -= 1;
+
+ return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_bit_string (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ PORT_Assert (state->place == duringBitString);
+ if (state->pending == 0) {
+ /* An empty bit string with some unused bits is invalid. */
+ if (state->bit_string_unused_bits) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ /* An empty bit string with no unused bits is OK. */
+ state->place = beforeEndOfContents;
+ }
+ return 0;
+ }
+
+ len = sec_asn1d_parse_leaf (state, buf, len);
+ if (state->place == beforeEndOfContents && state->dest != NULL) {
+ SECItem *item;
+
+ item = (SECItem *)(state->dest);
+ if (item->len)
+ item->len = (item->len << 3) - state->bit_string_unused_bits;
+ }
+
+ return len;
+}
+
+
+/*
+ * XXX All callers should be looking at return value to detect
+ * out-of-memory errors (and stop!).
+ */
+static struct subitem *
+sec_asn1d_add_to_subitems (sec_asn1d_state *state,
+ const void *data, unsigned long len,
+ PRBool copy_data)
+{
+ struct subitem *thing;
+
+ thing = (struct subitem*)sec_asn1d_zalloc (state->top->our_pool,
+ sizeof (struct subitem));
+ if (thing == NULL) {
+ state->top->status = decodeError;
+ return NULL;
+ }
+
+ if (copy_data) {
+ void *copy;
+ copy = sec_asn1d_alloc (state->top->our_pool, len);
+ if (copy == NULL) {
+ state->top->status = decodeError;
+ if (!state->top->our_pool)
+ PORT_Free(thing);
+ return NULL;
+ }
+ PORT_Memcpy (copy, data, len);
+ thing->data = copy;
+ } else {
+ thing->data = data;
+ }
+ thing->len = len;
+ thing->next = NULL;
+
+ if (state->subitems_head == NULL) {
+ PORT_Assert (state->subitems_tail == NULL);
+ state->subitems_head = state->subitems_tail = thing;
+ } else {
+ state->subitems_tail->next = thing;
+ state->subitems_tail = thing;
+ }
+
+ return thing;
+}
+
+
+static void
+sec_asn1d_record_any_header (sec_asn1d_state *state,
+ const char *buf,
+ unsigned long len)
+{
+ SECItem *item;
+
+ item = (SECItem *)(state->dest);
+ if (item != NULL && item->data != NULL) {
+ PORT_Assert (state->substring);
+ PORT_Memcpy (item->data + item->len, buf, len);
+ item->len += len;
+ } else {
+ sec_asn1d_add_to_subitems (state, buf, len, PR_TRUE);
+ }
+}
+
+
+/*
+ * We are moving along through the substrings of a constructed string,
+ * and have just finished parsing one -- we need to save our child data
+ * (if the child was not already writing directly into the destination)
+ * and then move forward by one.
+ *
+ * We also have to detect when we are done:
+ * - a definite-length encoding stops when our pending value hits 0
+ * - an indefinite-length encoding stops when our child is empty
+ * (which means it was the end-of-contents octets)
+ */
+static void
+sec_asn1d_next_substring (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ SECItem *item;
+ unsigned long child_consumed;
+ PRBool done;
+
+ PORT_Assert (state->place == duringConstructedString);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ child_consumed = child->consumed;
+ child->consumed = 0;
+ state->consumed += child_consumed;
+
+ done = PR_FALSE;
+
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (child_consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+
+ state->pending -= child_consumed;
+ if (state->pending == 0)
+ done = PR_TRUE;
+ } else {
+ PORT_Assert (state->indefinite);
+
+ item = (SECItem *)(child->dest);
+ if (item != NULL && item->data != NULL) {
+ /*
+ * Save the string away for later concatenation.
+ */
+ PORT_Assert (item->data != NULL);
+ sec_asn1d_add_to_subitems (state, item->data, item->len, PR_FALSE);
+ /*
+ * Clear the child item for the next round.
+ */
+ item->data = NULL;
+ item->len = 0;
+ }
+
+ /*
+ * If our child was just our end-of-contents octets, we are done.
+ */
+ if (child->endofcontents)
+ done = PR_TRUE;
+ }
+
+ /*
+ * Stop or do the next one.
+ */
+ if (done) {
+ child->place = notInUse;
+ state->place = afterConstructedString;
+ } else {
+ sec_asn1d_scrub_state (child);
+ state->top->current = child;
+ }
+}
+
+
+/*
+ * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
+ */
+static void
+sec_asn1d_next_in_group (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ unsigned long child_consumed;
+
+ PORT_Assert (state->place == duringGroup);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ child_consumed = child->consumed;
+ child->consumed = 0;
+ state->consumed += child_consumed;
+
+ /*
+ * If our child was just our end-of-contents octets, we are done.
+ */
+ if (child->endofcontents) {
+ /* XXX I removed the PORT_Assert (child->dest == NULL) because there
+ * was a bug in that a template that was a sequence of which also had
+ * a child of a sequence of, in an indefinite group was not working
+ * properly. This fix seems to work, (added the if statement below),
+ * and nothing appears broken, but I am putting this note here just
+ * in case. */
+ /*
+ * XXX No matter how many times I read that comment,
+ * I cannot figure out what case he was fixing. I believe what he
+ * did was deliberate, so I am loathe to touch it. I need to
+ * understand how it could ever be that child->dest != NULL but
+ * child->endofcontents is true, and why it is important to check
+ * that state->subitems_head is NULL. This really needs to be
+ * figured out, as I am not sure if the following code should be
+ * compensating for "offset", as is done a little farther below
+ * in the more normal case.
+ */
+ PORT_Assert (state->indefinite);
+ PORT_Assert (state->pending == 0);
+ if(child->dest && !state->subitems_head) {
+ sec_asn1d_add_to_subitems (state, child->dest, 0, PR_FALSE);
+ child->dest = NULL;
+ }
+
+ child->place = notInUse;
+ state->place = afterGroup;
+ return;
+ }
+
+ /*
+ * Do the "after" field notification for next in group.
+ */
+ sec_asn1d_notify_after (state->top, child->dest, child->depth);
+
+ /*
+ * Save it away (unless we are not storing).
+ */
+ if (child->dest != NULL) {
+ void *dest;
+
+ dest = child->dest;
+ dest = (char *)dest - child->theTemplate->offset;
+ sec_asn1d_add_to_subitems (state, dest, 0, PR_FALSE);
+ child->dest = NULL;
+ }
+
+ /*
+ * Account for those bytes; see if we are done.
+ */
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (child_consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+
+ state->pending -= child_consumed;
+ if (state->pending == 0) {
+ child->place = notInUse;
+ state->place = afterGroup;
+ return;
+ }
+ }
+
+ /*
+ * Do the "before" field notification for next item in group.
+ */
+ sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+ /*
+ * Now we do the next one.
+ */
+ sec_asn1d_scrub_state (child);
+
+ /* Initialize child state from the template */
+ sec_asn1d_init_state_based_on_template(child);
+
+ state->top->current = child;
+}
+
+
+/*
+ * We are moving along through a sequence; move forward by one,
+ * (detecting end-of-sequence when it happens).
+ * XXX The handling of "missing" is ugly. Fix it.
+ */
+static void
+sec_asn1d_next_in_sequence (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ unsigned long child_consumed;
+ PRBool child_missing;
+
+ PORT_Assert (state->place == duringSequence);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ /*
+ * Do the "after" field notification.
+ */
+ sec_asn1d_notify_after (state->top, child->dest, child->depth);
+
+ child_missing = (PRBool) child->missing;
+ child_consumed = child->consumed;
+ child->consumed = 0;
+
+ /*
+ * Take care of accounting.
+ */
+ if (child_missing) {
+ PORT_Assert (child->optional);
+ } else {
+ state->consumed += child_consumed;
+ /*
+ * Free any grandchild.
+ */
+ sec_asn1d_free_child (child, PR_FALSE);
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (child_consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ state->pending -= child_consumed;
+ if (state->pending == 0) {
+ child->theTemplate++;
+ while (child->theTemplate->kind != 0) {
+ if ((child->theTemplate->kind & SEC_ASN1_OPTIONAL) == 0) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ child->theTemplate++;
+ }
+ child->place = notInUse;
+ state->place = afterEndOfContents;
+ return;
+ }
+ }
+ }
+
+ /*
+ * Move forward.
+ */
+ child->theTemplate++;
+ if (child->theTemplate->kind == 0) {
+ /*
+ * We are done with this sequence.
+ */
+ child->place = notInUse;
+ if (state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else if (child_missing) {
+ /*
+ * We got to the end, but have a child that started parsing
+ * and ended up "missing". The only legitimate reason for
+ * this is that we had one or more optional fields at the
+ * end of our sequence, and we were encoded indefinite-length,
+ * so when we went looking for those optional fields we
+ * found our end-of-contents octets instead.
+ * (Yes, this is ugly; dunno a better way to handle it.)
+ * So, first confirm the situation, and then mark that we
+ * are done.
+ */
+ if (state->indefinite && child->endofcontents) {
+ PORT_Assert (child_consumed == 2);
+ if (child_consumed != 2) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ state->consumed += child_consumed;
+ state->place = afterEndOfContents;
+ }
+ } else {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ }
+ } else {
+ /*
+ * We have to finish out, maybe reading end-of-contents octets;
+ * let the normal logic do the right thing.
+ */
+ state->place = beforeEndOfContents;
+ }
+ } else {
+ unsigned char child_found_tag_modifiers = 0;
+ unsigned long child_found_tag_number = 0;
+
+ /*
+ * Reset state and push.
+ */
+ if (state->dest != NULL)
+ child->dest = (char *)state->dest + child->theTemplate->offset;
+
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+ if (child_missing) { /* if previous child was missing, copy the tag data we already have */
+ child_found_tag_modifiers = child->found_tag_modifiers;
+ child_found_tag_number = child->found_tag_number;
+ }
+ state->top->current = child;
+ child = sec_asn1d_init_state_based_on_template (child);
+ if (child_missing && child) {
+ child->place = afterIdentifier;
+ child->found_tag_modifiers = child_found_tag_modifiers;
+ child->found_tag_number = child_found_tag_number;
+ child->consumed = child_consumed;
+ if (child->underlying_kind == SEC_ASN1_ANY
+ && !child->top->filter_only) {
+ /*
+ * If the new field is an ANY, and we are storing, then
+ * we need to save the tag out. We would have done this
+ * already in the normal case, but since we were looking
+ * for an optional field, and we did not find it, we only
+ * now realize we need to save the tag.
+ */
+ unsigned char identifier;
+
+ /*
+ * Check that we did not end up with a high tag; for that
+ * we need to re-encode the tag into multiple bytes in order
+ * to store it back to look like what we parsed originally.
+ * In practice this does not happen, but for completeness
+ * sake it should probably be made to work at some point.
+ */
+ PORT_Assert (child_found_tag_number < SEC_ASN1_HIGH_TAG_NUMBER);
+ identifier = (unsigned char)(child_found_tag_modifiers | child_found_tag_number);
+ sec_asn1d_record_any_header (child, (char *) &identifier, 1);
+ }
+ }
+ }
+}
+
+
+static void
+sec_asn1d_concat_substrings (sec_asn1d_state *state)
+{
+ PORT_Assert (state->place == afterConstructedString);
+
+ if (state->subitems_head != NULL) {
+ struct subitem *substring;
+ unsigned long alloc_len, item_len;
+ unsigned char *where;
+ SECItem *item;
+ PRBool is_bit_string;
+
+ item_len = 0;
+ is_bit_string = (state->underlying_kind == SEC_ASN1_BIT_STRING)
+ ? PR_TRUE : PR_FALSE;
+
+ substring = state->subitems_head;
+ while (substring != NULL) {
+ /*
+ * All bit-string substrings except the last one should be
+ * a clean multiple of 8 bits.
+ */
+ if (is_bit_string && (substring->next == NULL)
+ && (substring->len & 0x7)) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ item_len += substring->len;
+ substring = substring->next;
+ }
+
+ if (is_bit_string) {
+ alloc_len = ((item_len + 7) >> 3);
+ } else {
+ /*
+ * Add 2 for the end-of-contents octets of an indefinite-length
+ * ANY that is *not* also an INNER. Because we zero-allocate
+ * below, all we need to do is increase the length here.
+ */
+ if (state->underlying_kind == SEC_ASN1_ANY && state->indefinite)
+ item_len += 2;
+ alloc_len = item_len;
+ }
+
+ item = (SECItem *)(state->dest);
+ PORT_Assert (item != NULL);
+ PORT_Assert (item->data == NULL);
+ item->data = (unsigned char*)sec_asn1d_zalloc (state->top->their_pool,
+ alloc_len);
+ if (item->data == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+ item->len = item_len;
+
+ where = item->data;
+ substring = state->subitems_head;
+ while (substring != NULL) {
+ if (is_bit_string)
+ item_len = (substring->len + 7) >> 3;
+ else
+ item_len = substring->len;
+ PORT_Memcpy (where, substring->data, item_len);
+ where += item_len;
+ substring = substring->next;
+ }
+
+ /*
+ * Because we use arenas and have a mark set, we later free
+ * everything we have allocated, so this does *not* present
+ * a memory leak (it is just temporarily left dangling).
+ */
+ state->subitems_head = state->subitems_tail = NULL;
+ }
+
+ state->place = afterEndOfContents;
+}
+
+
+static void
+sec_asn1d_concat_group (sec_asn1d_state *state)
+{
+ const void ***placep;
+
+ PORT_Assert (state->place == afterGroup);
+
+ placep = (const void***)state->dest;
+ PORT_Assert(state->subitems_head == NULL || placep != NULL);
+ if (placep != NULL) {
+ struct subitem *item;
+ const void **group;
+ int count;
+
+ count = 0;
+ item = state->subitems_head;
+ while (item != NULL) {
+ PORT_Assert (item->next != NULL || item == state->subitems_tail);
+ count++;
+ item = item->next;
+ }
+
+ group = (const void**)sec_asn1d_zalloc (state->top->their_pool,
+ (count + 1) * (sizeof(void *)));
+ if (group == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+
+ *placep = group;
+
+ item = state->subitems_head;
+ while (item != NULL) {
+ *group++ = item->data;
+ item = item->next;
+ }
+ *group = NULL;
+
+ /*
+ * Because we use arenas and have a mark set, we later free
+ * everything we have allocated, so this does *not* present
+ * a memory leak (it is just temporarily left dangling).
+ */
+ state->subitems_head = state->subitems_tail = NULL;
+ }
+
+ state->place = afterEndOfContents;
+}
+
+
+/*
+ * For those states that push a child to handle a subtemplate,
+ * "absorb" that child (transfer necessary information).
+ */
+static void
+sec_asn1d_absorb_child (sec_asn1d_state *state)
+{
+ /*
+ * There is absolutely supposed to be a child there.
+ */
+ PORT_Assert (state->child != NULL);
+
+ /*
+ * Inherit the missing status of our child, and do the ugly
+ * backing-up if necessary.
+ */
+ state->missing = state->child->missing;
+ if (state->missing) {
+ state->found_tag_number = state->child->found_tag_number;
+ state->found_tag_modifiers = state->child->found_tag_modifiers;
+ state->endofcontents = state->child->endofcontents;
+ }
+
+ /*
+ * Add in number of bytes consumed by child.
+ * (Only EXPLICIT should have already consumed bytes itself.)
+ */
+ PORT_Assert (state->place == afterExplicit || state->consumed == 0);
+ state->consumed += state->child->consumed;
+
+ /*
+ * Subtract from bytes pending; this only applies to a definite-length
+ * EXPLICIT field.
+ */
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ PORT_Assert (state->place == afterExplicit);
+
+ /*
+ * If we had a definite-length explicit, then what the child
+ * consumed should be what was left pending.
+ */
+ if (state->pending != state->child->consumed) {
+ if (state->pending < state->child->consumed) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ /*
+ * Okay, this is a hack. It *should* be an error whether
+ * pending is too big or too small, but it turns out that
+ * we had a bug in our *old* DER encoder that ended up
+ * counting an explicit header twice in the case where
+ * the underlying type was an ANY. So, because we cannot
+ * prevent receiving these (our own certificate server can
+ * send them to us), we need to be lenient and accept them.
+ * To do so, we need to pretend as if we read all of the
+ * bytes that the header said we would find, even though
+ * we actually came up short.
+ */
+ state->consumed += (state->pending - state->child->consumed);
+ }
+ state->pending = 0;
+ }
+
+ /*
+ * Indicate that we are done with child.
+ */
+ state->child->consumed = 0;
+
+ /*
+ * And move on to final state.
+ * (Technically everybody could move to afterEndOfContents except
+ * for an indefinite-length EXPLICIT; for simplicity though we assert
+ * that but let the end-of-contents code do the real determination.)
+ */
+ PORT_Assert (state->place == afterExplicit || (! state->indefinite));
+ state->place = beforeEndOfContents;
+}
+
+
+static void
+sec_asn1d_prepare_for_end_of_contents (sec_asn1d_state *state)
+{
+ PORT_Assert (state->place == beforeEndOfContents);
+
+ if (state->indefinite) {
+ state->place = duringEndOfContents;
+ state->pending = 2;
+ } else {
+ state->place = afterEndOfContents;
+ }
+}
+
+
+static unsigned long
+sec_asn1d_parse_end_of_contents (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned int i;
+
+ PORT_Assert (state->pending <= 2);
+ PORT_Assert (state->place == duringEndOfContents);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ if (state->pending < len)
+ len = state->pending;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] != 0) {
+ /*
+ * We expect to find only zeros; if not, just give up.
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+ }
+
+ state->pending -= len;
+
+ if (state->pending == 0) {
+ state->place = afterEndOfContents;
+ state->endofcontents = PR_TRUE;
+ }
+
+ return len;
+}
+
+
+static void
+sec_asn1d_pop_state (sec_asn1d_state *state)
+{
+#if 0 /* XXX I think this should always be handled explicitly by parent? */
+ /*
+ * Account for our child.
+ */
+ if (state->child != NULL) {
+ state->consumed += state->child->consumed;
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (state->child->consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ state->pending -= state->child->consumed;
+ }
+ }
+ state->child->consumed = 0;
+ }
+#endif /* XXX */
+
+ /*
+ * Free our child.
+ */
+ sec_asn1d_free_child (state, PR_FALSE);
+
+ /*
+ * Just make my parent be the current state. It will then clean
+ * up after me and free me (or reuse me).
+ */
+ state->top->current = state->parent;
+}
+
+static sec_asn1d_state *
+sec_asn1d_before_choice (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+
+ if (state->allocate) {
+ void *dest;
+
+ dest = sec_asn1d_zalloc(state->top->their_pool, state->theTemplate->size);
+ if ((void *)NULL == dest) {
+ state->top->status = decodeError;
+ return (sec_asn1d_state *)NULL;
+ }
+
+ state->dest = (char *)dest + state->theTemplate->offset;
+ }
+
+ child = sec_asn1d_push_state(state->top, state->theTemplate + 1,
+ (char *)state->dest - state->theTemplate->offset,
+ PR_FALSE);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ sec_asn1d_scrub_state(child);
+ child = sec_asn1d_init_state_based_on_template(child);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ child->optional = PR_TRUE;
+
+ state->place = duringChoice;
+
+ return child;
+}
+
+static sec_asn1d_state *
+sec_asn1d_during_choice (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child = state->child;
+
+ PORT_Assert((sec_asn1d_state *)NULL != child);
+
+ if (child->missing) {
+ unsigned char child_found_tag_modifiers = 0;
+ unsigned long child_found_tag_number = 0;
+ void * dest;
+
+ state->consumed += child->consumed;
+
+ if (child->endofcontents) {
+ /* This choice is probably the first item in a GROUP
+ ** (e.g. SET_OF) that was indefinite-length encoded.
+ ** We're actually at the end of that GROUP.
+ ** We look up the stack to be sure that we find
+ ** a state with indefinite length encoding before we
+ ** find a state (like a SEQUENCE) that is definite.
+ */
+ child->place = notInUse;
+ state->place = afterChoice;
+ state->endofcontents = PR_TRUE; /* propagate this up */
+ if (sec_asn1d_parent_allows_EOC(state))
+ return state;
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return NULL;
+ }
+
+ dest = (char *)child->dest - child->theTemplate->offset;
+ child->theTemplate++;
+
+ if (0 == child->theTemplate->kind) {
+ /* Ran out of choices */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return (sec_asn1d_state *)NULL;
+ }
+ child->dest = (char *)dest + child->theTemplate->offset;
+
+ /* cargo'd from next_in_sequence innards */
+ if (state->pending) {
+ PORT_Assert(!state->indefinite);
+ if (child->consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return NULL;
+ }
+ state->pending -= child->consumed;
+ if (0 == state->pending) {
+ /* XXX uh.. not sure if I should have stopped this
+ * from happening before. */
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return (sec_asn1d_state *)NULL;
+ }
+ }
+
+ child->consumed = 0;
+ sec_asn1d_scrub_state(child);
+
+ /* move it on top again */
+ state->top->current = child;
+
+ child_found_tag_modifiers = child->found_tag_modifiers;
+ child_found_tag_number = child->found_tag_number;
+
+ child = sec_asn1d_init_state_based_on_template(child);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ /* copy our findings to the new top */
+ child->found_tag_modifiers = child_found_tag_modifiers;
+ child->found_tag_number = child_found_tag_number;
+
+ child->optional = PR_TRUE;
+ child->place = afterIdentifier;
+
+ return child;
+ }
+ if ((void *)NULL != state->dest) {
+ /* Store the enum */
+ int *which = (int *)state->dest;
+ *which = (int)child->theTemplate->size;
+ }
+
+ child->place = notInUse;
+
+ state->place = afterChoice;
+ return state;
+}
+
+static void
+sec_asn1d_after_choice (sec_asn1d_state *state)
+{
+ state->consumed += state->child->consumed;
+ state->child->consumed = 0;
+ state->place = afterEndOfContents;
+ sec_asn1d_pop_state(state);
+}
+
+unsigned long
+sec_asn1d_uinteger(SECItem *src)
+{
+ unsigned long value;
+ int len;
+
+ if (src->len > 5 || (src->len > 4 && src->data[0] == 0))
+ return 0;
+
+ value = 0;
+ len = src->len;
+ while (len) {
+ value <<= 8;
+ value |= src->data[--len];
+ }
+ return value;
+}
+
+SECStatus
+SEC_ASN1DecodeInteger(SECItem *src, unsigned long *value)
+{
+ unsigned long v;
+ unsigned int i;
+
+ if (src == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (src->len > sizeof(unsigned long)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (src->data == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (src->data[0] & 0x80)
+ v = -1; /* signed and negative - start with all 1's */
+ else
+ v = 0;
+
+ for (i= 0; i < src->len; i++) {
+ /* shift in next byte */
+ v <<= 8;
+ v |= src->data[i];
+ }
+ *value = v;
+ return SECSuccess;
+}
+
+#ifdef DEBUG_ASN1D_STATES
+static void
+dump_states(SEC_ASN1DecoderContext *cx)
+{
+ sec_asn1d_state *state;
+ char kindBuf[256];
+
+ for (state = cx->current; state->parent; state = state->parent) {
+ ;
+ }
+
+ for (; state; state = state->child) {
+ int i;
+ for (i = 0; i < state->depth; i++) {
+ printf(" ");
+ }
+
+ i = formatKind(state->theTemplate->kind, kindBuf);
+ printf("%s: tmpl %08x, kind%s",
+ (state == cx->current) ? "STATE" : "State",
+ state->theTemplate,
+ kindBuf);
+ printf(" %s", (state->place >= 0 && state->place <= notInUse)
+ ? place_names[ state->place ]
+ : "(undefined)");
+ if (!i)
+ printf(", expect 0x%02x",
+ state->expect_tag_number | state->expect_tag_modifiers);
+
+ printf("%s%s%s %d\n",
+ state->indefinite ? ", indef" : "",
+ state->missing ? ", miss" : "",
+ state->endofcontents ? ", EOC" : "",
+ state->pending
+ );
+ }
+
+ return;
+}
+#endif /* DEBUG_ASN1D_STATES */
+
+SECStatus
+SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx,
+ const char *buf, unsigned long len)
+{
+ sec_asn1d_state *state = NULL;
+ unsigned long consumed;
+ SEC_ASN1EncodingPart what;
+ sec_asn1d_state *stateEnd = cx->current;
+
+ if (cx->status == needBytes)
+ cx->status = keepGoing;
+
+ while (cx->status == keepGoing) {
+ state = cx->current;
+ what = SEC_ASN1_Contents;
+ consumed = 0;
+#ifdef DEBUG_ASN1D_STATES
+ printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
+ (state->place >= 0 && state->place <= notInUse) ?
+ place_names[ state->place ] : "(undefined)",
+ (unsigned int)((unsigned char *)buf)[ consumed ],
+ buf, consumed);
+ dump_states(cx);
+#endif /* DEBUG_ASN1D_STATES */
+ switch (state->place) {
+ case beforeIdentifier:
+ consumed = sec_asn1d_parse_identifier (state, buf, len);
+ what = SEC_ASN1_Identifier;
+ break;
+ case duringIdentifier:
+ consumed = sec_asn1d_parse_more_identifier (state, buf, len);
+ what = SEC_ASN1_Identifier;
+ break;
+ case afterIdentifier:
+ sec_asn1d_confirm_identifier (state);
+ break;
+ case beforeLength:
+ consumed = sec_asn1d_parse_length (state, buf, len);
+ what = SEC_ASN1_Length;
+ break;
+ case duringLength:
+ consumed = sec_asn1d_parse_more_length (state, buf, len);
+ what = SEC_ASN1_Length;
+ break;
+ case afterLength:
+ sec_asn1d_prepare_for_contents (state);
+ break;
+ case beforeBitString:
+ consumed = sec_asn1d_parse_bit_string (state, buf, len);
+ break;
+ case duringBitString:
+ consumed = sec_asn1d_parse_more_bit_string (state, buf, len);
+ break;
+ case duringConstructedString:
+ sec_asn1d_next_substring (state);
+ break;
+ case duringGroup:
+ sec_asn1d_next_in_group (state);
+ break;
+ case duringLeaf:
+ consumed = sec_asn1d_parse_leaf (state, buf, len);
+ break;
+ case duringSaveEncoding:
+ sec_asn1d_reuse_encoding (state);
+ if (cx->status == decodeError) {
+ /* recursive call has already popped all states from stack.
+ ** Bail out quickly.
+ */
+ return SECFailure;
+ }
+ if (cx->status == needBytes) {
+ /* recursive call wanted more data. Fatal. Clean up below. */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ }
+ break;
+ case duringSequence:
+ sec_asn1d_next_in_sequence (state);
+ break;
+ case afterConstructedString:
+ sec_asn1d_concat_substrings (state);
+ break;
+ case afterExplicit:
+ case afterImplicit:
+ case afterInline:
+ case afterPointer:
+ sec_asn1d_absorb_child (state);
+ break;
+ case afterGroup:
+ sec_asn1d_concat_group (state);
+ break;
+ case afterSaveEncoding:
+ /* SEC_ASN1DecoderUpdate has called itself recursively to
+ ** decode SAVEd encoded data, and now is done decoding that.
+ ** Return to the calling copy of SEC_ASN1DecoderUpdate.
+ */
+ return SECSuccess;
+ case beforeEndOfContents:
+ sec_asn1d_prepare_for_end_of_contents (state);
+ break;
+ case duringEndOfContents:
+ consumed = sec_asn1d_parse_end_of_contents (state, buf, len);
+ what = SEC_ASN1_EndOfContents;
+ break;
+ case afterEndOfContents:
+ sec_asn1d_pop_state (state);
+ break;
+ case beforeChoice:
+ state = sec_asn1d_before_choice(state);
+ break;
+ case duringChoice:
+ state = sec_asn1d_during_choice(state);
+ break;
+ case afterChoice:
+ sec_asn1d_after_choice(state);
+ break;
+ case notInUse:
+ default:
+ /* This is not an error, but rather a plain old BUG! */
+ PORT_Assert (0);
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ break;
+ }
+
+ if (cx->status == decodeError)
+ break;
+
+ /* We should not consume more than we have. */
+ PORT_Assert (consumed <= len);
+ if (consumed > len) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ break;
+ }
+
+ /* It might have changed, so we have to update our local copy. */
+ state = cx->current;
+
+ /* If it is NULL, we have popped all the way to the top. */
+ if (state == NULL) {
+ PORT_Assert (consumed == 0);
+#if 0 /* XXX I want this here, but it seems that we have situations (like
+ * downloading a pkcs7 cert chain from some issuers) that give us a
+ * length which is greater than the entire encoding. So, we cannot
+ * have this be an error.
+ */
+ if (len > 0) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ } else
+#endif
+ cx->status = allDone;
+ break;
+ }
+ else if (state->theTemplate->kind == SEC_ASN1_SKIP_REST) {
+ cx->status = allDone;
+ break;
+ }
+
+ if (consumed == 0)
+ continue;
+
+ /*
+ * The following check is specifically looking for an ANY
+ * that is *not* also an INNER, because we need to save aside
+ * all bytes in that case -- the contents parts will get
+ * handled like all other contents, and the end-of-contents
+ * bytes are added by the concat code, but the outer header
+ * bytes need to get saved too, so we do them explicitly here.
+ */
+ if (state->underlying_kind == SEC_ASN1_ANY
+ && !cx->filter_only && (what == SEC_ASN1_Identifier
+ || what == SEC_ASN1_Length)) {
+ sec_asn1d_record_any_header (state, buf, consumed);
+ }
+
+ /*
+ * We had some number of good, accepted bytes. If the caller
+ * has registered to see them, pass them along.
+ */
+ if (state->top->filter_proc != NULL) {
+ int depth;
+
+ depth = state->depth;
+ if (what == SEC_ASN1_EndOfContents && !state->indefinite) {
+ PORT_Assert (state->parent != NULL
+ && state->parent->indefinite);
+ depth--;
+ PORT_Assert (depth == state->parent->depth);
+ }
+ (* state->top->filter_proc) (state->top->filter_arg,
+ buf, consumed, depth, what);
+ }
+
+ state->consumed += consumed;
+ buf += consumed;
+ len -= consumed;
+ }
+
+ if (cx->status == decodeError) {
+ while (state != NULL && stateEnd->parent!=state) {
+ sec_asn1d_free_child (state, PR_TRUE);
+ state = state->parent;
+ }
+#ifdef SEC_ASN1D_FREE_ON_ERROR /*
+ * XXX This does not work because we can
+ * end up leaving behind dangling pointers
+ * to stuff that was allocated. In order
+ * to make this really work (which would
+ * be a good thing, I think), we need to
+ * keep track of every place/pointer that
+ * was allocated and make sure to NULL it
+ * out before we then free back to the mark.
+ */
+ if (cx->their_pool != NULL) {
+ PORT_Assert (cx->their_mark != NULL);
+ PORT_ArenaRelease (cx->their_pool, cx->their_mark);
+ }
+#endif
+ return SECFailure;
+ }
+
+#if 0 /* XXX This is what I want, but cannot have because it seems we
+ * have situations (like when downloading a pkcs7 cert chain from
+ * some issuers) that give us a total length which is greater than
+ * the entire encoding. So, we have to allow allDone to have a
+ * remaining length greater than zero. I wanted to catch internal
+ * bugs with this, noticing when we do not have the right length.
+ * Oh well.
+ */
+ PORT_Assert (len == 0
+ && (cx->status == needBytes || cx->status == allDone));
+#else
+ PORT_Assert ((len == 0 && cx->status == needBytes)
+ || cx->status == allDone);
+#endif
+ return SECSuccess;
+}
+
+
+SECStatus
+SEC_ASN1DecoderFinish (SEC_ASN1DecoderContext *cx)
+{
+ SECStatus rv;
+
+ if (cx->status == needBytes) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ } else {
+ rv = SECSuccess;
+ }
+
+ /*
+ * XXX anything else that needs to be finished?
+ */
+
+ PORT_FreeArena (cx->our_pool, PR_TRUE);
+
+ return rv;
+}
+
+
+SEC_ASN1DecoderContext *
+SEC_ASN1DecoderStart (PRArenaPool *their_pool, void *dest,
+ const SEC_ASN1Template *theTemplate)
+{
+ PRArenaPool *our_pool;
+ SEC_ASN1DecoderContext *cx;
+
+ our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (our_pool == NULL)
+ return NULL;
+
+ cx = (SEC_ASN1DecoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
+ if (cx == NULL) {
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ cx->our_pool = our_pool;
+ if (their_pool != NULL) {
+ cx->their_pool = their_pool;
+#ifdef SEC_ASN1D_FREE_ON_ERROR
+ cx->their_mark = PORT_ArenaMark (their_pool);
+#endif
+ }
+
+ cx->status = needBytes;
+
+ if (sec_asn1d_push_state(cx, theTemplate, dest, PR_FALSE) == NULL
+ || sec_asn1d_init_state_based_on_template (cx->current) == NULL) {
+ /*
+ * Trouble initializing (probably due to failed allocations)
+ * requires that we just give up.
+ */
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ return cx;
+}
+
+
+void
+SEC_ASN1DecoderSetFilterProc (SEC_ASN1DecoderContext *cx,
+ SEC_ASN1WriteProc fn, void *arg,
+ PRBool only)
+{
+ /* check that we are "between" fields here */
+ PORT_Assert (cx->during_notify);
+
+ cx->filter_proc = fn;
+ cx->filter_arg = arg;
+ cx->filter_only = only;
+}
+
+
+void
+SEC_ASN1DecoderClearFilterProc (SEC_ASN1DecoderContext *cx)
+{
+ /* check that we are "between" fields here */
+ PORT_Assert (cx->during_notify);
+
+ cx->filter_proc = NULL;
+ cx->filter_arg = NULL;
+ cx->filter_only = PR_FALSE;
+}
+
+
+void
+SEC_ASN1DecoderSetNotifyProc (SEC_ASN1DecoderContext *cx,
+ SEC_ASN1NotifyProc fn, void *arg)
+{
+ cx->notify_proc = fn;
+ cx->notify_arg = arg;
+}
+
+
+void
+SEC_ASN1DecoderClearNotifyProc (SEC_ASN1DecoderContext *cx)
+{
+ cx->notify_proc = NULL;
+ cx->notify_arg = NULL; /* not necessary; just being clean */
+}
+
+void
+SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error)
+{
+ PORT_Assert(cx);
+ PORT_SetError(error);
+ cx->status = decodeError;
+}
+
+
+SECStatus
+SEC_ASN1Decode (PRArenaPool *poolp, void *dest,
+ const SEC_ASN1Template *theTemplate,
+ const char *buf, long len)
+{
+ SEC_ASN1DecoderContext *dcx;
+ SECStatus urv, frv;
+
+ dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate);
+ if (dcx == NULL)
+ return SECFailure;
+
+ urv = SEC_ASN1DecoderUpdate (dcx, buf, len);
+ frv = SEC_ASN1DecoderFinish (dcx);
+
+ if (urv != SECSuccess)
+ return urv;
+
+ return frv;
+}
+
+
+SECStatus
+SEC_ASN1DecodeItem (PRArenaPool *poolp, void *dest,
+ const SEC_ASN1Template *theTemplate,
+ const SECItem *src)
+{
+ return SEC_ASN1Decode (poolp, dest, theTemplate,
+ (const char *)src->data, src->len);
+}
+
+#ifdef DEBUG_ASN1D_STATES
+void sec_asn1d_Assert(const char *s, const char *file, PRIntn ln)
+{
+ printf("Assertion failed, \"%s\", file %s, line %d\n", s, file, ln);
+ fflush(stdout);
+}
+#endif
+
+/*
+ * Generic templates for individual/simple items and pointers to
+ * and sets of same.
+ *
+ * If you need to add a new one, please note the following:
+ * - For each new basic type you should add *four* templates:
+ * one plain, one PointerTo, one SequenceOf and one SetOf.
+ * - If the new type can be constructed (meaning, it is a
+ * *string* type according to BER/DER rules), then you should
+ * or-in SEC_ASN1_MAY_STREAM to the type in the basic template.
+ * See the definition of the OctetString template for an example.
+ * - It may not be obvious, but these are in *alphabetical*
+ * order based on the SEC_ASN1_XXX name; so put new ones in
+ * the appropriate place.
+ */
+
+const SEC_ASN1Template SEC_SequenceOfAnyTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToBitStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBitStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBitStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToBMPStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBMPStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToBooleanTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_BooleanTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBooleanTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_BooleanTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBooleanTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_BooleanTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_EnumeratedTemplate[] = {
+ { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) }
+};
+
+const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_EnumeratedTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_EnumeratedTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_EnumeratedTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_GeneralizedTimeTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_GeneralizedTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_GeneralizedTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToIA5StringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfIA5StringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToIntegerTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfIntegerTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfIntegerTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToNullTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfNullTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfNullTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToObjectIDTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_ObjectIDTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_ObjectIDTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SetOfObjectIDTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_ObjectIDTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_OctetStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfOctetStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_OctetStringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_PrintableStringTemplate[] = {
+ { SEC_ASN1_PRINTABLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToPrintableStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_PrintableStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_PrintableStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfPrintableStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_PrintableStringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_T61StringTemplate[] = {
+ { SEC_ASN1_T61_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToT61StringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_T61StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfT61StringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_T61StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfT61StringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_T61StringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_UniversalStringTemplate[] = {
+ { SEC_ASN1_UNIVERSAL_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToUniversalStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUniversalStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToUTCTimeTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUTCTimeTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToUTF8StringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_UTF8StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTF8StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUTF8StringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_UTF8StringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_VisibleStringTemplate[] = {
+ { SEC_ASN1_VISIBLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToVisibleStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_VisibleStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_VisibleStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfVisibleStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_VisibleStringTemplate }
+};
+
+#endif
+
+/*
+ * Template for skipping a subitem.
+ *
+ * Note that it only makes sense to use this for decoding (when you want
+ * to decode something where you are only interested in one or two of
+ * the fields); you cannot encode a SKIP!
+ */
+const SEC_ASN1Template SEC_SkipTemplate[] = {
+ { SEC_ASN1_SKIP }
+};
+
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs. Sigh.
+*/
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_EnumeratedTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToEnumeratedTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfAnyTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfObjectIDTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SkipTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UniversalStringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PrintableStringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_T61StringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToGeneralizedTimeTemplate)
+
diff --git a/lib/util/secasn1e.c b/lib/util/secasn1e.c
new file mode 100644
index 000000000..5a98f0946
--- /dev/null
+++ b/lib/util/secasn1e.c
@@ -0,0 +1,1615 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id$
+ */
+
+#include "secasn1.h"
+
+typedef enum {
+ beforeHeader,
+ duringContents,
+ duringGroup,
+ duringSequence,
+ afterContents,
+ afterImplicit,
+ afterInline,
+ afterPointer,
+ afterChoice,
+ notInUse
+} sec_asn1e_parse_place;
+
+typedef enum {
+ allDone,
+ encodeError,
+ keepGoing,
+ needBytes
+} sec_asn1e_parse_status;
+
+typedef enum {
+ hdr_normal = 0, /* encode header normally */
+ hdr_any = 1, /* header already encoded in content */
+ hdr_decoder = 2, /* template only used by decoder. skip it. */
+ hdr_optional = 3, /* optional component, to be omitted */
+ hdr_placeholder = 4 /* place holder for from_buf content */
+} sec_asn1e_hdr_encoding;
+
+typedef struct sec_asn1e_state_struct {
+ SEC_ASN1EncoderContext *top;
+ const SEC_ASN1Template *theTemplate;
+ void *src;
+
+ struct sec_asn1e_state_struct *parent; /* aka prev */
+ struct sec_asn1e_state_struct *child; /* aka next */
+
+ sec_asn1e_parse_place place; /* where we are in encoding process */
+
+ /*
+ * XXX explain the next fields as clearly as possible...
+ */
+ unsigned char tag_modifiers;
+ unsigned char tag_number;
+ unsigned long underlying_kind;
+
+ int depth;
+
+ PRBool isExplicit, /* we are handling an isExplicit header */
+ indefinite, /* need end-of-contents */
+ is_string, /* encoding a simple string or an ANY */
+ may_stream, /* when streaming, do indefinite encoding */
+ optional, /* omit field if it has no contents */
+ disallowStreaming; /* disallow streaming in all sub-templates */
+} sec_asn1e_state;
+
+/*
+ * An "outsider" will have an opaque pointer to this, created by calling
+ * SEC_ASN1EncoderStart(). It will be passed back in to all subsequent
+ * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
+ * it is passed to SEC_ASN1EncoderFinish().
+ */
+struct sec_EncoderContext_struct {
+ PRArenaPool *our_pool; /* for our internal allocs */
+
+ sec_asn1e_state *current;
+ sec_asn1e_parse_status status;
+
+ PRBool streaming;
+ PRBool from_buf;
+
+ SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
+ void *notify_arg; /* argument to notify_proc */
+ PRBool during_notify; /* true during call to notify_proc */
+
+ SEC_ASN1WriteProc output_proc; /* pass encoded bytes to this */
+ void *output_arg; /* argument to that function */
+};
+
+
+static sec_asn1e_state *
+sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
+ const SEC_ASN1Template *theTemplate,
+ const void *src, PRBool new_depth)
+{
+ sec_asn1e_state *state, *new_state;
+
+ state = cx->current;
+
+ new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool,
+ sizeof(*new_state));
+ if (new_state == NULL) {
+ cx->status = encodeError;
+ return NULL;
+ }
+
+ new_state->top = cx;
+ new_state->parent = state;
+ new_state->theTemplate = theTemplate;
+ new_state->place = notInUse;
+ if (src != NULL)
+ new_state->src = (char *)src + theTemplate->offset;
+
+ if (state != NULL) {
+ new_state->depth = state->depth;
+ if (new_depth)
+ new_state->depth++;
+ state->child = new_state;
+ }
+
+ cx->current = new_state;
+ return new_state;
+}
+
+
+static void
+sec_asn1e_scrub_state (sec_asn1e_state *state)
+{
+ /*
+ * Some default "scrubbing".
+ * XXX right set of initializations?
+ */
+ state->place = beforeHeader;
+ state->indefinite = PR_FALSE;
+}
+
+
+static void
+sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static void
+sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static sec_asn1e_state *
+sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
+{
+ PRBool isExplicit, is_string, may_stream, optional, universal;
+ PRBool disallowStreaming;
+ unsigned char tag_modifiers;
+ unsigned long encode_kind, under_kind;
+ unsigned long tag_number;
+ PRBool isInline = PR_FALSE;
+
+
+ encode_kind = state->theTemplate->kind;
+
+ universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+ optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+ PORT_Assert (!(isExplicit && universal)); /* bad templates */
+
+ may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+ disallowStreaming = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_NO_STREAM;
+
+ /* Just clear this to get it out of the way; we do not need it here */
+ encode_kind &= ~SEC_ASN1_DYNAMIC;
+
+ if( encode_kind & SEC_ASN1_CHOICE ) {
+ under_kind = SEC_ASN1_CHOICE;
+ } else if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) ||
+ (!universal && !isExplicit)) {
+ const SEC_ASN1Template *subt;
+ void *src = NULL;
+
+ PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
+
+ sec_asn1e_scrub_state (state);
+
+ if (encode_kind & SEC_ASN1_POINTER) {
+ src = *(void **)state->src;
+ state->place = afterPointer;
+
+ if (src == NULL) {
+ /*
+ * If this is optional, but NULL, then the field does
+ * not need to be encoded. In this case we are done;
+ * we do not want to push a subtemplate.
+ */
+ if (optional)
+ return state;
+
+ /*
+ * XXX this is an error; need to figure out
+ * how to handle this
+ */
+ }
+ } else {
+ src = state->src;
+ if (encode_kind & SEC_ASN1_INLINE) {
+ /* check that there are no extraneous bits */
+ /* PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); */
+ state->place = afterInline;
+ isInline = PR_TRUE;
+ } else {
+ /*
+ * Save the tag modifiers and tag number here before moving
+ * on to the next state in case this is a member of a
+ * SEQUENCE OF
+ */
+ state->tag_modifiers = (unsigned char)
+ (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
+ state->tag_number = (unsigned char)
+ (encode_kind & SEC_ASN1_TAGNUM_MASK);
+
+ state->place = afterImplicit;
+ state->optional = optional;
+ }
+ }
+
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE);
+ if (isInline && optional) {
+ /* we only handle a very limited set of optional inline cases at
+ this time */
+ if (PR_FALSE != SEC_ASN1IsTemplateSimple(subt)) {
+ /* we now know that the target is a SECItem*, so we can check
+ if the source contains one */
+ SECItem* target = (SECItem*)state->src;
+ if (!target || !target->data || !target->len) {
+ /* no valid data to encode subtemplate */
+ return state;
+ }
+ } else {
+ PORT_Assert(0); /* complex templates are not handled as
+ inline optional */
+ }
+ }
+ state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);
+ if (state == NULL)
+ return state;
+
+ if (universal) {
+ /*
+ * This is a POINTER or INLINE; just init based on that
+ * and we are done.
+ */
+ return sec_asn1e_init_state_based_on_template (state);
+ }
+
+ /*
+ * This is an implicit, non-universal (meaning, application-private
+ * or context-specific) field. This results in a "magic" tag but
+ * encoding based on the underlying type. We pushed a new state
+ * that is based on the subtemplate (the underlying type), but
+ * now we will sort of alias it to give it some of our properties
+ * (tag, optional status, etc.).
+ *
+ * NB: ALL the following flags in the subtemplate are disallowed
+ * and/or ignored: EXPLICIT, OPTIONAL, INNER, INLINE, POINTER.
+ */
+
+ under_kind = state->theTemplate->kind;
+ if ((under_kind & SEC_ASN1_MAY_STREAM) && !disallowStreaming) {
+ may_stream = PR_TRUE;
+ }
+ under_kind &= ~(SEC_ASN1_MAY_STREAM | SEC_ASN1_DYNAMIC);
+ } else {
+ under_kind = encode_kind;
+ }
+
+ /*
+ * Sanity check that there are no unwanted bits marked in under_kind.
+ * These bits were either removed above (after we recorded them) or
+ * they simply should not be found (signalling a bad/broken template).
+ * XXX is this the right set of bits to test here? (i.e. need to add
+ * or remove any?)
+ */
+#define UNEXPECTED_FLAGS \
+ (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_SKIP | SEC_ASN1_INNER | \
+ SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_INLINE | SEC_ASN1_POINTER)
+
+ PORT_Assert ((under_kind & UNEXPECTED_FLAGS) == 0);
+ under_kind &= ~UNEXPECTED_FLAGS;
+#undef UNEXPECTED_FLAGS
+
+ if (encode_kind & SEC_ASN1_ANY) {
+ PORT_Assert (encode_kind == under_kind);
+ tag_modifiers = 0;
+ tag_number = 0;
+ is_string = PR_TRUE;
+ } else {
+ tag_modifiers = (unsigned char)
+ (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
+ /*
+ * XXX This assumes only single-octet identifiers. To handle
+ * the HIGH TAG form we would need to do some more work, especially
+ * in how to specify them in the template, because right now we
+ * do not provide a way to specify more *tag* bits in encode_kind.
+ */
+ tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
+
+ is_string = PR_FALSE;
+ switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
+ case SEC_ASN1_SET:
+ /*
+ * XXX A plain old SET (as opposed to a SET OF) is not implemented.
+ * If it ever is, remove this assert...
+ */
+ PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
+ /* fallthru */
+ case SEC_ASN1_SEQUENCE:
+ tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+ break;
+ case SEC_ASN1_BIT_STRING:
+ case SEC_ASN1_BMP_STRING:
+ case SEC_ASN1_GENERALIZED_TIME:
+ case SEC_ASN1_IA5_STRING:
+ case SEC_ASN1_OCTET_STRING:
+ case SEC_ASN1_PRINTABLE_STRING:
+ case SEC_ASN1_T61_STRING:
+ case SEC_ASN1_UNIVERSAL_STRING:
+ case SEC_ASN1_UTC_TIME:
+ case SEC_ASN1_UTF8_STRING:
+ case SEC_ASN1_VISIBLE_STRING:
+ /*
+ * We do not yet know if we will be constructing the string,
+ * so we have to wait to do this final tag modification.
+ */
+ is_string = PR_TRUE;
+ break;
+ }
+ }
+
+ state->tag_modifiers = tag_modifiers;
+ state->tag_number = (unsigned char)tag_number;
+ state->underlying_kind = under_kind;
+ state->isExplicit = isExplicit;
+ state->may_stream = may_stream;
+ state->is_string = is_string;
+ state->optional = optional;
+ state->disallowStreaming = disallowStreaming;
+
+ sec_asn1e_scrub_state (state);
+
+ return state;
+}
+
+
+static void
+sec_asn1e_write_part (sec_asn1e_state *state,
+ const char *buf, unsigned long len,
+ SEC_ASN1EncodingPart part)
+{
+ SEC_ASN1EncoderContext *cx;
+
+ cx = state->top;
+ (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
+}
+
+
+/*
+ * XXX This assumes only single-octet identifiers. To handle
+ * the HIGH TAG form we would need to modify this interface and
+ * teach it to properly encode the special form.
+ */
+static void
+sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
+{
+ char byte;
+
+ byte = (char) value;
+ sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
+}
+
+int
+SEC_ASN1EncodeLength(unsigned char *buf,int value) {
+ int lenlen;
+
+ lenlen = SEC_ASN1LengthLength (value);
+ if (lenlen == 1) {
+ buf[0] = value;
+ } else {
+ int i;
+
+ i = lenlen - 1;
+ buf[0] = 0x80 | i;
+ while (i) {
+ buf[i--] = value;
+ value >>= 8;
+ }
+ PORT_Assert (value == 0);
+ }
+ return lenlen;
+}
+
+static void
+sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
+ PRBool indefinite)
+{
+ int lenlen;
+ unsigned char buf[sizeof(unsigned long) + 1];
+
+ if (indefinite) {
+ PORT_Assert (value == 0);
+ buf[0] = 0x80;
+ lenlen = 1;
+ } else {
+ lenlen = SEC_ASN1EncodeLength(buf,value);
+ }
+
+ sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
+}
+
+
+static void
+sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
+ const char *buf, unsigned long len)
+{
+ sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
+}
+
+
+static void
+sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
+{
+ const char eoc[2] = {0, 0};
+
+ sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
+}
+
+static int
+sec_asn1e_which_choice
+(
+ void *src,
+ const SEC_ASN1Template *theTemplate
+)
+{
+ int rv;
+ unsigned int which = *(unsigned int *)src;
+
+ for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
+ if( which == theTemplate->size ) {
+ return rv;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned long
+sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src,
+ PRBool disallowStreaming, PRBool insideIndefinite,
+ sec_asn1e_hdr_encoding *pHdrException)
+{
+ unsigned long encode_kind, underlying_kind;
+ PRBool isExplicit, optional, universal, may_stream;
+ unsigned long len;
+
+ /*
+ * This function currently calculates the length in all cases
+ * except the following: when writing out the contents of a
+ * template that belongs to a state where it was a sub-template
+ * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
+ * optional bit set. The information that the parent is optional
+ * and that we should return the length of 0 when that length is
+ * present since that means the optional field is no longer present.
+ * So we add the disallowStreaming flag which is passed in when
+ * writing the contents, but for all recursive calls to
+ * sec_asn1e_contents_length, we pass PR_FALSE, because this
+ * function correctly calculates the length for children templates
+ * from that point on. Confused yet? At least you didn't have
+ * to figure it out. ;) -javi
+ */
+ encode_kind = theTemplate->kind;
+
+ universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+ optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+ PORT_Assert (!(isExplicit && universal)); /* bad templates */
+
+ may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+ /* Just clear this to get it out of the way; we do not need it here */
+ encode_kind &= ~SEC_ASN1_DYNAMIC;
+
+ if (encode_kind & SEC_ASN1_NO_STREAM) {
+ disallowStreaming = PR_TRUE;
+ }
+ encode_kind &= ~SEC_ASN1_NO_STREAM;
+
+ if (encode_kind & SEC_ASN1_CHOICE) {
+ void *src2;
+ int indx = sec_asn1e_which_choice(src, theTemplate);
+ if (0 == indx) {
+ /* XXX set an error? "choice not found" */
+ /* state->top->status = encodeError; */
+ return 0;
+ }
+
+ src2 = (void *)
+ ((char *)src - theTemplate->offset + theTemplate[indx].offset);
+
+ return sec_asn1e_contents_length(&theTemplate[indx], src2,
+ disallowStreaming, insideIndefinite,
+ pHdrException);
+ }
+
+ if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
+ /* XXX any bits we want to disallow (PORT_Assert against) here? */
+ theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
+ if (encode_kind & SEC_ASN1_POINTER) {
+ src = *(void **)src;
+ if (src == NULL) {
+ *pHdrException = optional ? hdr_optional : hdr_normal;
+ return 0;
+ }
+ } else if (encode_kind & SEC_ASN1_INLINE) {
+ /* check that there are no extraneous bits */
+ if (optional) {
+ if (PR_FALSE != SEC_ASN1IsTemplateSimple(theTemplate)) {
+ /* we now know that the target is a SECItem*, so we can check
+ if the source contains one */
+ SECItem* target = (SECItem*)src;
+ if (!target || !target->data || !target->len) {
+ /* no valid data to encode subtemplate */
+ *pHdrException = hdr_optional;
+ return 0;
+ }
+ } else {
+ PORT_Assert(0); /* complex templates not handled as inline
+ optional */
+ }
+ }
+ }
+
+ src = (char *)src + theTemplate->offset;
+
+ /* recurse to find the length of the subtemplate */
+ len = sec_asn1e_contents_length (theTemplate, src, disallowStreaming,
+ insideIndefinite, pHdrException);
+ if (len == 0 && optional) {
+ *pHdrException = hdr_optional;
+ } else if (isExplicit) {
+ if (*pHdrException == hdr_any) {
+ /* *we* do not want to add in a header,
+ ** but our caller still does.
+ */
+ *pHdrException = hdr_normal;
+ } else if (*pHdrException == hdr_normal) {
+ /* if the inner content exists, our length is
+ * len(identifier) + len(length) + len(innercontent)
+ * XXX we currently assume len(identifier) == 1;
+ * to support a high-tag-number this would need to be smarter.
+ */
+ len += 1 + SEC_ASN1LengthLength (len);
+ }
+ }
+ return len;
+ }
+ underlying_kind = encode_kind;
+
+ /* This is only used in decoding; it plays no part in encoding. */
+ if (underlying_kind & SEC_ASN1_SAVE) {
+ /* check that there are no extraneous bits */
+ PORT_Assert (underlying_kind == SEC_ASN1_SAVE);
+ *pHdrException = hdr_decoder;
+ return 0;
+ }
+
+#define UNEXPECTED_FLAGS \
+ (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_INLINE | SEC_ASN1_POINTER |\
+ SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_SAVE | SEC_ASN1_SKIP)
+
+ /* Having any of these bits is not expected here... */
+ PORT_Assert ((underlying_kind & UNEXPECTED_FLAGS) == 0);
+ underlying_kind &= ~UNEXPECTED_FLAGS;
+#undef UNEXPECTED_FLAGS
+
+ if (underlying_kind & SEC_ASN1_CHOICE) {
+ void *src2;
+ int indx = sec_asn1e_which_choice(src, theTemplate);
+ if (0 == indx) {
+ /* XXX set an error? "choice not found" */
+ /* state->top->status = encodeError; */
+ return 0;
+ }
+
+ src2 = (void *)
+ ((char *)src - theTemplate->offset + theTemplate[indx].offset);
+ len = sec_asn1e_contents_length(&theTemplate[indx], src2,
+ disallowStreaming, insideIndefinite,
+ pHdrException);
+ } else {
+ switch (underlying_kind) {
+ case SEC_ASN1_SEQUENCE_OF:
+ case SEC_ASN1_SET_OF:
+ {
+ const SEC_ASN1Template *tmpt;
+ void *sub_src;
+ unsigned long sub_len;
+ void **group;
+
+ len = 0;
+
+ group = *(void ***)src;
+ if (group == NULL)
+ break;
+
+ tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
+
+ for (; *group != NULL; group++) {
+ sub_src = (char *)(*group) + tmpt->offset;
+ sub_len = sec_asn1e_contents_length (tmpt, sub_src,
+ disallowStreaming,
+ insideIndefinite,
+ pHdrException);
+ len += sub_len;
+ /*
+ * XXX The 1 below is the presumed length of the identifier;
+ * to support a high-tag-number this would need to be smarter.
+ */
+ if (*pHdrException == hdr_normal)
+ len += 1 + SEC_ASN1LengthLength (sub_len);
+ }
+ }
+ break;
+
+ case SEC_ASN1_SEQUENCE:
+ case SEC_ASN1_SET:
+ {
+ const SEC_ASN1Template *tmpt;
+ void *sub_src;
+ unsigned long sub_len;
+
+ len = 0;
+ for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {
+ sub_src = (char *)src + tmpt->offset;
+ sub_len = sec_asn1e_contents_length (tmpt, sub_src,
+ disallowStreaming,
+ insideIndefinite,
+ pHdrException);
+ len += sub_len;
+ /*
+ * XXX The 1 below is the presumed length of the identifier;
+ * to support a high-tag-number this would need to be smarter.
+ */
+ if (*pHdrException == hdr_normal)
+ len += 1 + SEC_ASN1LengthLength (sub_len);
+ }
+ }
+ break;
+
+ case SEC_ASN1_BIT_STRING:
+ /* convert bit length to byte */
+ len = (((SECItem *)src)->len + 7) >> 3;
+ /* bit string contents involve an extra octet */
+ if (len)
+ len++;
+ break;
+
+ case SEC_ASN1_INTEGER:
+ /* ASN.1 INTEGERs are signed.
+ * If the source is an unsigned integer, the encoder will need
+ * to handle the conversion here.
+ */
+ {
+ unsigned char *buf = ((SECItem *)src)->data;
+ SECItemType integerType = ((SECItem *)src)->type;
+ len = ((SECItem *)src)->len;
+ while (len > 0) {
+ if (*buf != 0) {
+ if (*buf & 0x80 && integerType == siUnsignedInteger) {
+ len++; /* leading zero needed to make number signed */
+ }
+ break; /* reached beginning of number */
+ }
+ if (len == 1) {
+ break; /* the number 0 */
+ }
+ if (buf[1] & 0x80) {
+ break; /* leading zero already present */
+ }
+ /* extraneous leading zero, keep going */
+ buf++;
+ len--;
+ }
+ }
+ break;
+
+ default:
+ len = ((SECItem *)src)->len;
+ break;
+ } /* end switch */
+
+#ifndef WHAT_PROBLEM_DOES_THIS_SOLVE
+ /* if we're streaming, we may have a secitem w/len 0 as placeholder */
+ if (!len && insideIndefinite && may_stream && !disallowStreaming) {
+ len = 1;
+ }
+#endif
+ } /* end else */
+
+ if (len == 0 && optional)
+ *pHdrException = hdr_optional;
+ else if (underlying_kind == SEC_ASN1_ANY)
+ *pHdrException = hdr_any;
+ else
+ *pHdrException = hdr_normal;
+
+ return len;
+}
+
+
+static void
+sec_asn1e_write_header (sec_asn1e_state *state)
+{
+ unsigned long contents_length;
+ unsigned char tag_number, tag_modifiers;
+ sec_asn1e_hdr_encoding hdrException = hdr_normal;
+ PRBool indefinite = PR_FALSE;
+
+ PORT_Assert (state->place == beforeHeader);
+
+ tag_number = state->tag_number;
+ tag_modifiers = state->tag_modifiers;
+
+ if (state->underlying_kind == SEC_ASN1_ANY) {
+ state->place = duringContents;
+ return;
+ }
+
+ if (state->underlying_kind & SEC_ASN1_CHOICE) {
+ int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
+ if( 0 == indx ) {
+ /* XXX set an error? "choice not found" */
+ state->top->status = encodeError;
+ return;
+ }
+ state->place = afterChoice;
+ state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
+ (char *)state->src - state->theTemplate->offset,
+ PR_TRUE);
+ if (state) {
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1e_notify_before (state->top, state->src, state->depth);
+ state = sec_asn1e_init_state_based_on_template (state);
+ }
+ return;
+ }
+
+ /* The !isString test below is apparently intended to ensure that all
+ ** constructed types receive indefinite length encoding.
+ */
+ indefinite = (PRBool)
+ (state->top->streaming && state->may_stream &&
+ (state->top->from_buf || !state->is_string));
+
+ /*
+ * If we are doing a definite-length encoding, first we have to
+ * walk the data structure to calculate the entire contents length.
+ * If we are doing an indefinite-length encoding, we still need to
+ * know if the contents is:
+ * optional and to be omitted, or
+ * an ANY (header is pre-encoded), or
+ * a SAVE or some other kind of template used only by the decoder.
+ * So, we call this function either way.
+ */
+ contents_length = sec_asn1e_contents_length (state->theTemplate,
+ state->src,
+ state->disallowStreaming,
+ indefinite,
+ &hdrException);
+ /*
+ * We might be told explicitly not to put out a header.
+ * But it can also be the case, via a pushed subtemplate, that
+ * sec_asn1e_contents_length could not know that this field is
+ * really optional. So check for that explicitly, too.
+ */
+ if (hdrException != hdr_normal ||
+ (contents_length == 0 && state->optional)) {
+ state->place = afterContents;
+ if (state->top->streaming &&
+ state->may_stream &&
+ state->top->from_buf) {
+ /* we did not find an optional indefinite string, so we
+ * don't encode it. However, if TakeFromBuf is on, we stop
+ * here anyway to give our caller a chance to intercept at the
+ * same point where we would stop if the field were present.
+ */
+ state->top->status = needBytes;
+ }
+ return;
+ }
+
+ if (indefinite) {
+ /*
+ * We need to put out an indefinite-length encoding.
+ * The only universal types that can be constructed are SETs,
+ * SEQUENCEs, and strings; so check that it is one of those,
+ * or that it is not universal (e.g. context-specific).
+ */
+ state->indefinite = PR_TRUE;
+ PORT_Assert ((tag_number == SEC_ASN1_SET)
+ || (tag_number == SEC_ASN1_SEQUENCE)
+ || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
+ || state->is_string);
+ tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+ contents_length = 0;
+ }
+
+ sec_asn1e_write_identifier_bytes (state,
+ (unsigned char)(tag_number | tag_modifiers));
+ sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
+
+ if (contents_length == 0 && !state->indefinite) {
+ /*
+ * If no real contents to encode, then we are done with this field.
+ */
+ state->place = afterContents;
+ return;
+ }
+
+ /*
+ * An EXPLICIT is nothing but an outer header, which we have already
+ * written. Now we need to do the inner header and contents.
+ */
+ if (state->isExplicit) {
+ const SEC_ASN1Template *subt =
+ SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE);
+ state->place = afterContents;
+ state = sec_asn1e_push_state (state->top, subt, state->src, PR_TRUE);
+ if (state != NULL)
+ state = sec_asn1e_init_state_based_on_template (state);
+ return;
+ }
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_SET_OF:
+ case SEC_ASN1_SEQUENCE_OF:
+ /*
+ * We need to push a child to handle each member.
+ */
+ {
+ void **group;
+ const SEC_ASN1Template *subt;
+
+ group = *(void ***)state->src;
+ if (group == NULL || *group == NULL) {
+ /*
+ * Group is empty; we are done.
+ */
+ state->place = afterContents;
+ return;
+ }
+ state->place = duringGroup;
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
+ PR_TRUE);
+ state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
+ if (state != NULL)
+ state = sec_asn1e_init_state_based_on_template (state);
+ }
+ break;
+
+ case SEC_ASN1_SEQUENCE:
+ case SEC_ASN1_SET:
+ /*
+ * We need to push a child to handle the individual fields.
+ */
+ state->place = duringSequence;
+ state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
+ state->src, PR_TRUE);
+ if (state != NULL) {
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1e_notify_before (state->top, state->src, state->depth);
+ state = sec_asn1e_init_state_based_on_template (state);
+ }
+ break;
+
+ default:
+ /*
+ * I think we do not need to do anything else.
+ * XXX Correct?
+ */
+ state->place = duringContents;
+ break;
+ }
+}
+
+
+static void
+sec_asn1e_write_contents_from_buf (sec_asn1e_state *state,
+ const char *buf, unsigned long len)
+{
+ PORT_Assert (state->place == duringContents);
+ PORT_Assert (state->top->from_buf);
+ PORT_Assert (state->may_stream && !state->disallowStreaming);
+
+ /*
+ * Probably they just turned on "take from buf", but have not
+ * yet given us any bytes. If there is nothing in the buffer
+ * then we have nothing to do but return and wait.
+ */
+ if (buf == NULL || len == 0) {
+ state->top->status = needBytes;
+ return;
+ }
+ /*
+ * We are streaming, reading from a passed-in buffer.
+ * This means we are encoding a simple string or an ANY.
+ * For the former, we need to put out a substring, with its
+ * own identifier and length. For an ANY, we just write it
+ * out as is (our caller is required to ensure that it
+ * is a properly encoded entity).
+ */
+ PORT_Assert (state->is_string); /* includes ANY */
+ if (state->underlying_kind != SEC_ASN1_ANY) {
+ unsigned char identifier;
+
+ /*
+ * Create the identifier based on underlying_kind. We cannot
+ * use tag_number and tag_modifiers because this can be an
+ * implicitly encoded field. In that case, the underlying
+ * substrings *are* encoded with their real tag.
+ */
+ identifier = (unsigned char)
+ (state->underlying_kind & SEC_ASN1_TAG_MASK);
+ /*
+ * The underlying kind should just be a simple string; there
+ * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
+ */
+ PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
+ /*
+ * Write out the tag and length for the substring.
+ */
+ sec_asn1e_write_identifier_bytes (state, identifier);
+ if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
+ char byte;
+ /*
+ * Assume we have a length in bytes but we need to output
+ * a proper bit string. This interface only works for bit
+ * strings that are full multiples of 8. If support for
+ * real, variable length bit strings is needed then the
+ * caller will have to know to pass in a bit length instead
+ * of a byte length and then this code will have to
+ * perform the encoding necessary (length written is length
+ * in bytes plus 1, and the first octet of string is the
+ * number of bits remaining between the end of the bit
+ * string and the next byte boundary).
+ */
+ sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
+ byte = 0;
+ sec_asn1e_write_contents_bytes (state, &byte, 1);
+ } else {
+ sec_asn1e_write_length_bytes (state, len, PR_FALSE);
+ }
+ }
+ sec_asn1e_write_contents_bytes (state, buf, len);
+ state->top->status = needBytes;
+}
+
+static void
+sec_asn1e_write_contents (sec_asn1e_state *state)
+{
+ unsigned long len = 0;
+
+ PORT_Assert (state->place == duringContents);
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_SET:
+ case SEC_ASN1_SEQUENCE:
+ PORT_Assert (0);
+ break;
+
+ case SEC_ASN1_BIT_STRING:
+ {
+ SECItem *item;
+ char rem;
+
+ item = (SECItem *)state->src;
+ len = (item->len + 7) >> 3;
+ rem = (unsigned char)((len << 3) - item->len); /* remaining bits */
+ sec_asn1e_write_contents_bytes (state, &rem, 1);
+ sec_asn1e_write_contents_bytes (state, (char *) item->data, len);
+ }
+ break;
+
+ case SEC_ASN1_BMP_STRING:
+ /* The number of bytes must be divisable by 2 */
+ if ((((SECItem *)state->src)->len) % 2) {
+ SEC_ASN1EncoderContext *cx;
+
+ cx = state->top;
+ cx->status = encodeError;
+ break;
+ }
+ /* otherwise, fall through to write the content */
+ goto process_string;
+
+ case SEC_ASN1_UNIVERSAL_STRING:
+ /* The number of bytes must be divisable by 4 */
+ if ((((SECItem *)state->src)->len) % 4) {
+ SEC_ASN1EncoderContext *cx;
+
+ cx = state->top;
+ cx->status = encodeError;
+ break;
+ }
+ /* otherwise, fall through to write the content */
+ goto process_string;
+
+ case SEC_ASN1_INTEGER:
+ /* ASN.1 INTEGERs are signed. If the source is an unsigned
+ * integer, the encoder will need to handle the conversion here.
+ */
+ {
+ unsigned int blen;
+ unsigned char *buf;
+ SECItemType integerType;
+ blen = ((SECItem *)state->src)->len;
+ buf = ((SECItem *)state->src)->data;
+ integerType = ((SECItem *)state->src)->type;
+ while (blen > 0) {
+ if (*buf & 0x80 && integerType == siUnsignedInteger) {
+ char zero = 0; /* write a leading 0 */
+ sec_asn1e_write_contents_bytes(state, &zero, 1);
+ /* and then the remaining buffer */
+ sec_asn1e_write_contents_bytes(state,
+ (char *)buf, blen);
+ break;
+ }
+ /* Check three possibilities:
+ * 1. No leading zeros, msb of MSB is not 1;
+ * 2. The number is zero itself;
+ * 3. Encoding a signed integer with a leading zero,
+ * keep the zero so that the number is positive.
+ */
+ if (*buf != 0 ||
+ blen == 1 ||
+ (buf[1] & 0x80 && integerType != siUnsignedInteger) )
+ {
+ sec_asn1e_write_contents_bytes(state,
+ (char *)buf, blen);
+ break;
+ }
+ /* byte is 0, continue */
+ buf++;
+ blen--;
+ }
+ }
+ /* done with this content */
+ break;
+
+process_string:
+ default:
+ {
+ SECItem *item;
+
+ item = (SECItem *)state->src;
+ sec_asn1e_write_contents_bytes (state, (char *) item->data,
+ item->len);
+ }
+ break;
+ }
+ state->place = afterContents;
+}
+
+/*
+ * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
+ */
+static void
+sec_asn1e_next_in_group (sec_asn1e_state *state)
+{
+ sec_asn1e_state *child;
+ void **group;
+ void *member;
+
+ PORT_Assert (state->place == duringGroup);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ group = *(void ***)state->src;
+
+ /*
+ * Find placement of current item.
+ */
+ member = (char *)(state->child->src) - child->theTemplate->offset;
+ while (*group != member)
+ group++;
+
+ /*
+ * Move forward to next item.
+ */
+ group++;
+ if (*group == NULL) {
+ /*
+ * That was our last one; we are done now.
+ */
+ child->place = notInUse;
+ state->place = afterContents;
+ return;
+ }
+ child->src = (char *)(*group) + child->theTemplate->offset;
+
+ /*
+ * Re-"push" child.
+ */
+ sec_asn1e_scrub_state (child);
+ state->top->current = child;
+}
+
+
+/*
+ * We are moving along through a sequence; move forward by one,
+ * (detecting end-of-sequence when it happens).
+ */
+static void
+sec_asn1e_next_in_sequence (sec_asn1e_state *state)
+{
+ sec_asn1e_state *child;
+
+ PORT_Assert (state->place == duringSequence);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ /*
+ * Do the "after" field notification.
+ */
+ sec_asn1e_notify_after (state->top, child->src, child->depth);
+
+ /*
+ * Move forward.
+ */
+ child->theTemplate++;
+ if (child->theTemplate->kind == 0) {
+ /*
+ * We are done with this sequence.
+ */
+ child->place = notInUse;
+ state->place = afterContents;
+ return;
+ }
+
+ /*
+ * Reset state and push.
+ */
+
+ child->src = (char *)state->src + child->theTemplate->offset;
+
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1e_notify_before (state->top, child->src, child->depth);
+
+ state->top->current = child;
+ (void) sec_asn1e_init_state_based_on_template (child);
+}
+
+
+static void
+sec_asn1e_after_contents (sec_asn1e_state *state)
+{
+ PORT_Assert (state->place == afterContents);
+
+ if (state->indefinite)
+ sec_asn1e_write_end_of_contents_bytes (state);
+
+ /*
+ * Just make my parent be the current state. It will then clean
+ * up after me and free me (or reuse me).
+ */
+ state->top->current = state->parent;
+}
+
+
+/*
+ * This function is called whether or not we are streaming; if we
+ * *are* streaming, our caller can also instruct us to take bytes
+ * from the passed-in buffer (at buf, for length len, which is likely
+ * bytes but could even mean bits if the current field is a bit string).
+ * If we have been so instructed, we will gobble up bytes from there
+ * (rather than from our src structure) and output them, and then
+ * we will just return, expecting to be called again -- either with
+ * more bytes or after our caller has instructed us that we are done
+ * (for now) with the buffer.
+ */
+SECStatus
+SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
+ const char *buf, unsigned long len)
+{
+ sec_asn1e_state *state;
+
+ if (cx->status == needBytes) {
+ cx->status = keepGoing;
+ }
+
+ while (cx->status == keepGoing) {
+ state = cx->current;
+ switch (state->place) {
+ case beforeHeader:
+ sec_asn1e_write_header (state);
+ break;
+ case duringContents:
+ if (cx->from_buf)
+ sec_asn1e_write_contents_from_buf (state, buf, len);
+ else
+ sec_asn1e_write_contents (state);
+ break;
+ case duringGroup:
+ sec_asn1e_next_in_group (state);
+ break;
+ case duringSequence:
+ sec_asn1e_next_in_sequence (state);
+ break;
+ case afterContents:
+ sec_asn1e_after_contents (state);
+ break;
+ case afterImplicit:
+ case afterInline:
+ case afterPointer:
+ case afterChoice:
+ /*
+ * These states are more documentation than anything.
+ * They just need to force a pop.
+ */
+ PORT_Assert (!state->indefinite);
+ state->place = afterContents;
+ break;
+ case notInUse:
+ default:
+ /* This is not an error, but rather a plain old BUG! */
+ PORT_Assert (0);
+ cx->status = encodeError;
+ break;
+ }
+
+ if (cx->status == encodeError)
+ break;
+
+ /* It might have changed, so we have to update our local copy. */
+ state = cx->current;
+
+ /* If it is NULL, we have popped all the way to the top. */
+ if (state == NULL) {
+ cx->status = allDone;
+ break;
+ }
+ }
+
+ if (cx->status == encodeError) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+
+void
+SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
+{
+ /*
+ * XXX anything else that needs to be finished?
+ */
+
+ PORT_FreeArena (cx->our_pool, PR_FALSE);
+}
+
+
+SEC_ASN1EncoderContext *
+SEC_ASN1EncoderStart (const void *src, const SEC_ASN1Template *theTemplate,
+ SEC_ASN1WriteProc output_proc, void *output_arg)
+{
+ PRArenaPool *our_pool;
+ SEC_ASN1EncoderContext *cx;
+
+ our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (our_pool == NULL)
+ return NULL;
+
+ cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
+ if (cx == NULL) {
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ cx->our_pool = our_pool;
+ cx->output_proc = output_proc;
+ cx->output_arg = output_arg;
+
+ cx->status = keepGoing;
+
+ if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
+ || sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
+ /*
+ * Trouble initializing (probably due to failed allocations)
+ * requires that we just give up.
+ */
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ return cx;
+}
+
+
+/*
+ * XXX Do we need a FilterProc, too?
+ */
+
+
+void
+SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
+ SEC_ASN1NotifyProc fn, void *arg)
+{
+ cx->notify_proc = fn;
+ cx->notify_arg = arg;
+}
+
+
+void
+SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
+{
+ cx->notify_proc = NULL;
+ cx->notify_arg = NULL; /* not necessary; just being clean */
+}
+
+void
+SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
+{
+ PORT_Assert(cx);
+ PORT_SetError(error);
+ cx->status = encodeError;
+}
+
+void
+SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
+{
+ /* XXX is there a way to check that we are "between" fields here? */
+
+ cx->streaming = PR_TRUE;
+}
+
+
+void
+SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
+{
+ /* XXX is there a way to check that we are "between" fields here? */
+
+ cx->streaming = PR_FALSE;
+}
+
+
+void
+SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
+{
+ /*
+ * XXX is there a way to check that we are "between" fields here? this
+ * needs to include a check for being in between groups of items in
+ * a SET_OF or SEQUENCE_OF.
+ */
+ PORT_Assert (cx->streaming);
+
+ cx->from_buf = PR_TRUE;
+}
+
+
+void
+SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
+{
+ /* we should actually be taking from buf *now* */
+ PORT_Assert (cx->from_buf);
+ if (! cx->from_buf) /* if not, just do nothing */
+ return;
+
+ cx->from_buf = PR_FALSE;
+
+ if (cx->status == needBytes) {
+ cx->status = keepGoing;
+ cx->current->place = afterContents;
+ }
+}
+
+
+SECStatus
+SEC_ASN1Encode (const void *src, const SEC_ASN1Template *theTemplate,
+ SEC_ASN1WriteProc output_proc, void *output_arg)
+{
+ SEC_ASN1EncoderContext *ecx;
+ SECStatus rv;
+
+ ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
+ if (ecx == NULL)
+ return SECFailure;
+
+ rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
+
+ SEC_ASN1EncoderFinish (ecx);
+ return rv;
+}
+
+
+/*
+ * XXX depth and data_kind are unused; is there a PC way to silence warnings?
+ * (I mean "politically correct", not anything to do with intel/win platform)
+ */
+static void
+sec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind)
+{
+ unsigned long *count;
+
+ count = (unsigned long*)arg;
+ PORT_Assert (count != NULL);
+
+ *count += len;
+}
+
+
+/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
+static void
+sec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind)
+{
+ SECItem *dest;
+
+ dest = (SECItem*)arg;
+ PORT_Assert (dest != NULL);
+
+ PORT_Memcpy (dest->data + dest->len, buf, len);
+ dest->len += len;
+}
+
+
+/*
+ * Allocate an entire SECItem, or just the data part of it, to hold
+ * "len" bytes of stuff. Allocate from the given pool, if specified,
+ * otherwise just do a vanilla PORT_Alloc.
+ *
+ * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
+ */
+static SECItem *
+sec_asn1e_allocate_item (PRArenaPool *poolp, SECItem *dest, unsigned long len)
+{
+ if (poolp != NULL) {
+ void *release;
+
+ release = PORT_ArenaMark (poolp);
+ if (dest == NULL)
+ dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
+ if (dest != NULL) {
+ dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
+ if (dest->data == NULL) {
+ dest = NULL;
+ }
+ }
+ if (dest == NULL) {
+ /* one or both allocations failed; release everything */
+ PORT_ArenaRelease (poolp, release);
+ } else {
+ /* everything okay; unmark the arena */
+ PORT_ArenaUnmark (poolp, release);
+ }
+ } else {
+ SECItem *indest;
+
+ indest = dest;
+ if (dest == NULL)
+ dest = (SECItem*)PORT_Alloc (sizeof(SECItem));
+ if (dest != NULL) {
+ dest->type = siBuffer;
+ dest->data = (unsigned char*)PORT_Alloc (len);
+ if (dest->data == NULL) {
+ if (indest == NULL)
+ PORT_Free (dest);
+ dest = NULL;
+ }
+ }
+ }
+
+ return dest;
+}
+
+
+SECItem *
+SEC_ASN1EncodeItem (PRArenaPool *poolp, SECItem *dest, const void *src,
+ const SEC_ASN1Template *theTemplate)
+{
+ unsigned long encoding_length;
+ SECStatus rv;
+
+ PORT_Assert (dest == NULL || dest->data == NULL);
+
+ encoding_length = 0;
+ rv = SEC_ASN1Encode (src, theTemplate,
+ sec_asn1e_encode_item_count, &encoding_length);
+ if (rv != SECSuccess)
+ return NULL;
+
+ dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
+ if (dest == NULL)
+ return NULL;
+
+ /* XXX necessary? This really just checks for a bug in the allocate fn */
+ PORT_Assert (dest->data != NULL);
+ if (dest->data == NULL)
+ return NULL;
+
+ dest->len = 0;
+ (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
+
+ PORT_Assert (encoding_length == dest->len);
+ return dest;
+}
+
+
+static SECItem *
+sec_asn1e_integer(PRArenaPool *poolp, SECItem *dest, unsigned long value,
+ PRBool is_unsigned)
+{
+ unsigned long copy;
+ unsigned char sign;
+ int len = 0;
+
+ /*
+ * Determine the length of the encoded value (minimum of 1).
+ */
+ copy = value;
+ do {
+ len++;
+ sign = (unsigned char)(copy & 0x80);
+ copy >>= 8;
+ } while (copy);
+
+ /*
+ * If 'value' is non-negative, and the high bit of the last
+ * byte we counted was set, we need to add one to the length so
+ * we put a high-order zero byte in the encoding.
+ */
+ if (sign && (is_unsigned || (long)value >= 0))
+ len++;
+
+ /*
+ * Allocate the item (if necessary) and the data pointer within.
+ */
+ dest = sec_asn1e_allocate_item (poolp, dest, len);
+ if (dest == NULL)
+ return NULL;
+
+ /*
+ * Store the value, byte by byte, in the item.
+ */
+ dest->len = len;
+ while (len) {
+ dest->data[--len] = (unsigned char)value;
+ value >>= 8;
+ }
+ PORT_Assert (value == 0);
+
+ return dest;
+}
+
+
+SECItem *
+SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value)
+{
+ return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
+}
+
+
+SECItem *
+SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
+ SECItem *dest, unsigned long value)
+{
+ return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
+}
diff --git a/lib/util/secasn1t.h b/lib/util/secasn1t.h
new file mode 100644
index 000000000..c662b0ea4
--- /dev/null
+++ b/lib/util/secasn1t.h
@@ -0,0 +1,270 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Types for encoding/decoding of ASN.1 using BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id$
+ */
+
+#ifndef _SECASN1T_H_
+#define _SECASN1T_H_
+
+#include "utilrename.h"
+
+/*
+** An array of these structures defines a BER/DER encoding for an object.
+**
+** The array usually starts with a dummy entry whose kind is SEC_ASN1_SEQUENCE;
+** such an array is terminated with an entry where kind == 0. (An array
+** which consists of a single component does not require a second dummy
+** entry -- the array is only searched as long as previous component(s)
+** instruct it.)
+*/
+typedef struct sec_ASN1Template_struct {
+ /*
+ ** Kind of item being decoded/encoded, including tags and modifiers.
+ */
+ unsigned long kind;
+
+ /*
+ ** The value is the offset from the base of the structure to the
+ ** field that holds the value being decoded/encoded.
+ */
+ unsigned long offset;
+
+ /*
+ ** When kind suggests it (SEC_ASN1_POINTER, SEC_ASN1_GROUP, SEC_ASN1_INLINE,
+ ** or a component that is *not* a SEC_ASN1_UNIVERSAL), this points to
+ ** a sub-template for nested encoding/decoding,
+ ** OR, iff SEC_ASN1_DYNAMIC is set, then this is a pointer to a pointer
+ ** to a function which will return the appropriate template when called
+ ** at runtime. NOTE! that explicit level of indirection, which is
+ ** necessary because ANSI does not allow you to store a function
+ ** pointer directly as a "void *" so we must store it separately and
+ ** dereference it to get at the function pointer itself.
+ */
+ const void *sub;
+
+ /*
+ ** In the first element of a template array, the value is the size
+ ** of the structure to allocate when this template is being referenced
+ ** by another template via SEC_ASN1_POINTER or SEC_ASN1_GROUP.
+ ** In all other cases, the value is ignored.
+ */
+ unsigned int size;
+} SEC_ASN1Template;
+
+
+/* default size used for allocation of encoding/decoding stuff */
+/* XXX what is the best value here? */
+#define SEC_ASN1_DEFAULT_ARENA_SIZE (2048)
+
+/*
+** BER/DER values for ASN.1 identifier octets.
+*/
+#define SEC_ASN1_TAG_MASK 0xff
+
+/*
+ * BER/DER universal type tag numbers.
+ * The values are defined by the X.208 standard; do not change them!
+ * NOTE: if you add anything to this list, you must add code to secasn1d.c
+ * to accept the tag, and probably also to secasn1e.c to encode it.
+ * XXX It appears some have been added recently without being added to
+ * the code; so need to go through the list now and double-check them all.
+ * (Look especially at those added in revision 1.10.)
+ */
+#define SEC_ASN1_TAGNUM_MASK 0x1f
+#define SEC_ASN1_BOOLEAN 0x01
+#define SEC_ASN1_INTEGER 0x02
+#define SEC_ASN1_BIT_STRING 0x03
+#define SEC_ASN1_OCTET_STRING 0x04
+#define SEC_ASN1_NULL 0x05
+#define SEC_ASN1_OBJECT_ID 0x06
+#define SEC_ASN1_OBJECT_DESCRIPTOR 0x07
+/* External type and instance-of type 0x08 */
+#define SEC_ASN1_REAL 0x09
+#define SEC_ASN1_ENUMERATED 0x0a
+#define SEC_ASN1_EMBEDDED_PDV 0x0b
+#define SEC_ASN1_UTF8_STRING 0x0c
+/* 0x0d */
+/* 0x0e */
+/* 0x0f */
+#define SEC_ASN1_SEQUENCE 0x10
+#define SEC_ASN1_SET 0x11
+#define SEC_ASN1_NUMERIC_STRING 0x12
+#define SEC_ASN1_PRINTABLE_STRING 0x13
+#define SEC_ASN1_T61_STRING 0x14
+#define SEC_ASN1_VIDEOTEX_STRING 0x15
+#define SEC_ASN1_IA5_STRING 0x16
+#define SEC_ASN1_UTC_TIME 0x17
+#define SEC_ASN1_GENERALIZED_TIME 0x18
+#define SEC_ASN1_GRAPHIC_STRING 0x19
+#define SEC_ASN1_VISIBLE_STRING 0x1a
+#define SEC_ASN1_GENERAL_STRING 0x1b
+#define SEC_ASN1_UNIVERSAL_STRING 0x1c
+/* 0x1d */
+#define SEC_ASN1_BMP_STRING 0x1e
+#define SEC_ASN1_HIGH_TAG_NUMBER 0x1f
+#define SEC_ASN1_TELETEX_STRING SEC_ASN1_T61_STRING
+
+/*
+** Modifiers to type tags. These are also specified by a/the
+** standard, and must not be changed.
+*/
+
+#define SEC_ASN1_METHOD_MASK 0x20
+#define SEC_ASN1_PRIMITIVE 0x00
+#define SEC_ASN1_CONSTRUCTED 0x20
+
+#define SEC_ASN1_CLASS_MASK 0xc0
+#define SEC_ASN1_UNIVERSAL 0x00
+#define SEC_ASN1_APPLICATION 0x40
+#define SEC_ASN1_CONTEXT_SPECIFIC 0x80
+#define SEC_ASN1_PRIVATE 0xc0
+
+/*
+** Our additions, used for templates.
+** These are not defined by any standard; the values are used internally only.
+** Just be careful to keep them out of the low 8 bits.
+** XXX finish comments
+*/
+#define SEC_ASN1_OPTIONAL 0x00100
+#define SEC_ASN1_EXPLICIT 0x00200
+#define SEC_ASN1_ANY 0x00400
+#define SEC_ASN1_INLINE 0x00800
+#define SEC_ASN1_POINTER 0x01000
+#define SEC_ASN1_GROUP 0x02000 /* with SET or SEQUENCE means
+ * SET OF or SEQUENCE OF */
+#define SEC_ASN1_DYNAMIC 0x04000 /* subtemplate is found by calling
+ * a function at runtime */
+#define SEC_ASN1_SKIP 0x08000 /* skip a field; only for decoding */
+#define SEC_ASN1_INNER 0x10000 /* with ANY means capture the
+ * contents only (not the id, len,
+ * or eoc); only for decoding */
+#define SEC_ASN1_SAVE 0x20000 /* stash away the encoded bytes first;
+ * only for decoding */
+#define SEC_ASN1_MAY_STREAM 0x40000 /* field or one of its sub-fields may
+ * stream in and so should encode as
+ * indefinite-length when streaming
+ * has been indicated; only for
+ * encoding */
+#define SEC_ASN1_SKIP_REST 0x80000 /* skip all following fields;
+ only for decoding */
+#define SEC_ASN1_CHOICE 0x100000 /* pick one from a template */
+#define SEC_ASN1_NO_STREAM 0X200000 /* This entry will not stream
+ even if the sub-template says
+ streaming is possible. Helps
+ to solve ambiguities with potential
+ streaming entries that are
+ optional */
+#define SEC_ASN1_DEBUG_BREAK 0X400000 /* put this in your template and the
+ decoder will assert when it
+ processes it. Only for use with
+ SEC_QuickDERDecodeItem */
+
+
+
+/* Shorthand/Aliases */
+#define SEC_ASN1_SEQUENCE_OF (SEC_ASN1_GROUP | SEC_ASN1_SEQUENCE)
+#define SEC_ASN1_SET_OF (SEC_ASN1_GROUP | SEC_ASN1_SET)
+#define SEC_ASN1_ANY_CONTENTS (SEC_ASN1_ANY | SEC_ASN1_INNER)
+
+/* Maximum depth of nested SEQUENCEs and SETs */
+#define SEC_ASN1D_MAX_DEPTH 32
+
+/*
+** Function used for SEC_ASN1_DYNAMIC.
+** "arg" is a pointer to the structure being encoded/decoded
+** "enc", when true, means that we are encoding (false means decoding)
+*/
+typedef const SEC_ASN1Template * SEC_ASN1TemplateChooser(void *arg, PRBool enc);
+typedef SEC_ASN1TemplateChooser * SEC_ASN1TemplateChooserPtr;
+
+#if defined(_WIN32) || defined(ANDROID)
+#define SEC_ASN1_GET(x) NSS_Get_##x(NULL, PR_FALSE)
+#define SEC_ASN1_SUB(x) &p_NSS_Get_##x
+#define SEC_ASN1_XTRN SEC_ASN1_DYNAMIC
+#define SEC_ASN1_MKSUB(x) \
+static const SEC_ASN1TemplateChooserPtr p_NSS_Get_##x = &NSS_Get_##x;
+#else
+#define SEC_ASN1_GET(x) x
+#define SEC_ASN1_SUB(x) x
+#define SEC_ASN1_XTRN 0
+#define SEC_ASN1_MKSUB(x)
+#endif
+
+#define SEC_ASN1_CHOOSER_DECLARE(x) \
+extern const SEC_ASN1Template * NSS_Get_##x (void *arg, PRBool enc);
+
+#define SEC_ASN1_CHOOSER_IMPLEMENT(x) \
+const SEC_ASN1Template * NSS_Get_##x(void * arg, PRBool enc) \
+{ return x; }
+
+/*
+** Opaque object used by the decoder to store state.
+*/
+typedef struct sec_DecoderContext_struct SEC_ASN1DecoderContext;
+
+/*
+** Opaque object used by the encoder to store state.
+*/
+typedef struct sec_EncoderContext_struct SEC_ASN1EncoderContext;
+
+/*
+ * This is used to describe to a filter function the bytes that are
+ * being passed to it. This is only useful when the filter is an "outer"
+ * one, meaning it expects to get *all* of the bytes not just the
+ * contents octets.
+ */
+typedef enum {
+ SEC_ASN1_Identifier = 0,
+ SEC_ASN1_Length = 1,
+ SEC_ASN1_Contents = 2,
+ SEC_ASN1_EndOfContents = 3
+} SEC_ASN1EncodingPart;
+
+/*
+ * Type of the function pointer used either for decoding or encoding,
+ * when doing anything "funny" (e.g. manipulating the data stream)
+ */
+typedef void (* SEC_ASN1NotifyProc)(void *arg, PRBool before,
+ void *dest, int real_depth);
+
+/*
+ * Type of the function pointer used for grabbing encoded bytes.
+ * This can be used during either encoding or decoding, as follows...
+ *
+ * When decoding, this can be used to filter the encoded bytes as they
+ * are parsed. This is what you would do if you wanted to process the data
+ * along the way (like to decrypt it, or to perform a hash on it in order
+ * to do a signature check later). See SEC_ASN1DecoderSetFilterProc().
+ * When processing only part of the encoded bytes is desired, you "watch"
+ * for the field(s) you are interested in with a "notify proc" (see
+ * SEC_ASN1DecoderSetNotifyProc()) and for even finer granularity (e.g. to
+ * ignore all by the contents bytes) you pay attention to the "data_kind"
+ * parameter.
+ *
+ * When encoding, this is the specification for the output function which
+ * will receive the bytes as they are encoded. The output function can
+ * perform any postprocessing necessary (like hashing (some of) the data
+ * to create a digest that gets included at the end) as well as shoving
+ * the data off wherever it needs to go. (In order to "tune" any processing,
+ * you can set a "notify proc" as described above in the decoding case.)
+ *
+ * The parameters:
+ * - "arg" is an opaque pointer that you provided at the same time you
+ * specified a function of this type
+ * - "data" is a buffer of length "len", containing the encoded bytes
+ * - "depth" is how deep in a nested encoding we are (it is not usually
+ * valuable, but can be useful sometimes so I included it)
+ * - "data_kind" tells you if these bytes are part of the ASN.1 encoded
+ * octets for identifier, length, contents, or end-of-contents
+ */
+typedef void (* SEC_ASN1WriteProc)(void *arg,
+ const char *data, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind);
+
+#endif /* _SECASN1T_H_ */
diff --git a/lib/util/secasn1u.c b/lib/util/secasn1u.c
new file mode 100644
index 000000000..98bdbe0af
--- /dev/null
+++ b/lib/util/secasn1u.c
@@ -0,0 +1,99 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Utility routines to complement the ASN.1 encoding and decoding functions.
+ *
+ * $Id$
+ */
+
+#include "secasn1.h"
+
+
+/*
+ * We have a length that needs to be encoded; how many bytes will the
+ * encoding take?
+ *
+ * The rules are that 0 - 0x7f takes one byte (the length itself is the
+ * entire encoding); everything else takes one plus the number of bytes
+ * in the length.
+ */
+int
+SEC_ASN1LengthLength (unsigned long len)
+{
+ int lenlen = 1;
+
+ if (len > 0x7f) {
+ do {
+ lenlen++;
+ len >>= 8;
+ } while (len);
+ }
+
+ return lenlen;
+}
+
+
+/*
+ * XXX Move over (and rewrite as appropriate) the rest of the
+ * stuff in dersubr.c!
+ */
+
+
+/*
+ * Find the appropriate subtemplate for the given template.
+ * This may involve calling a "chooser" function, or it may just
+ * be right there. In either case, it is expected to *have* a
+ * subtemplate; this is asserted in debug builds (in non-debug
+ * builds, NULL will be returned).
+ *
+ * "thing" is a pointer to the structure being encoded/decoded
+ * "encoding", when true, means that we are in the process of encoding
+ * (as opposed to in the process of decoding)
+ */
+const SEC_ASN1Template *
+SEC_ASN1GetSubtemplate (const SEC_ASN1Template *theTemplate, void *thing,
+ PRBool encoding)
+{
+ const SEC_ASN1Template *subt = NULL;
+
+ PORT_Assert (theTemplate->sub != NULL);
+ if (theTemplate->sub != NULL) {
+ if (theTemplate->kind & SEC_ASN1_DYNAMIC) {
+ SEC_ASN1TemplateChooserPtr chooserp;
+
+ chooserp = *(SEC_ASN1TemplateChooserPtr *) theTemplate->sub;
+ if (chooserp) {
+ if (thing != NULL)
+ thing = (char *)thing - theTemplate->offset;
+ subt = (* chooserp)(thing, encoding);
+ }
+ } else {
+ subt = (SEC_ASN1Template*)theTemplate->sub;
+ }
+ }
+ return subt;
+}
+
+PRBool SEC_ASN1IsTemplateSimple(const SEC_ASN1Template *theTemplate)
+{
+ if (!theTemplate) {
+ return PR_TRUE; /* it doesn't get any simpler than NULL */
+ }
+ /* only templates made of one primitive type or a choice of primitive
+ types are considered simple */
+ if (! (theTemplate->kind & (~SEC_ASN1_TAGNUM_MASK))) {
+ return PR_TRUE; /* primitive type */
+ }
+ if (!(theTemplate->kind & SEC_ASN1_CHOICE)) {
+ return PR_FALSE; /* no choice means not simple */
+ }
+ while (++theTemplate && theTemplate->kind) {
+ if (theTemplate->kind & (~SEC_ASN1_TAGNUM_MASK)) {
+ return PR_FALSE; /* complex type */
+ }
+ }
+ return PR_TRUE; /* choice of primitive types */
+}
+
diff --git a/lib/util/seccomon.h b/lib/util/seccomon.h
new file mode 100644
index 000000000..a29655627
--- /dev/null
+++ b/lib/util/seccomon.h
@@ -0,0 +1,94 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * seccomon.h - common data structures for security libraries
+ *
+ * This file should have lowest-common-denominator datastructures
+ * for security libraries. It should not be dependent on any other
+ * headers, and should not require linking with any libraries.
+ *
+ * $Id$
+ */
+
+#ifndef _SECCOMMON_H_
+#define _SECCOMMON_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+
+
+#ifdef __cplusplus
+# define SEC_BEGIN_PROTOS extern "C" {
+# define SEC_END_PROTOS }
+#else
+# define SEC_BEGIN_PROTOS
+# define SEC_END_PROTOS
+#endif
+
+#include "secport.h"
+
+typedef enum {
+ siBuffer = 0,
+ siClearDataBuffer = 1,
+ siCipherDataBuffer = 2,
+ siDERCertBuffer = 3,
+ siEncodedCertBuffer = 4,
+ siDERNameBuffer = 5,
+ siEncodedNameBuffer = 6,
+ siAsciiNameString = 7,
+ siAsciiString = 8,
+ siDEROID = 9,
+ siUnsignedInteger = 10,
+ siUTCTime = 11,
+ siGeneralizedTime = 12,
+ siVisibleString = 13,
+ siUTF8String = 14,
+ siBMPString = 15
+} SECItemType;
+
+typedef struct SECItemStr SECItem;
+
+struct SECItemStr {
+ SECItemType type;
+ unsigned char *data;
+ unsigned int len;
+};
+
+typedef struct SECItemArrayStr SECItemArray;
+
+struct SECItemArrayStr {
+ SECItem *items;
+ unsigned int len;
+};
+
+/*
+** A status code. Status's are used by procedures that return status
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong. Correct testing of status codes:
+**
+** SECStatus rv;
+** rv = some_function (some_argument);
+** if (rv != SECSuccess)
+** do_an_error_thing();
+**
+*/
+typedef enum _SECStatus {
+ SECWouldBlock = -2,
+ SECFailure = -1,
+ SECSuccess = 0
+} SECStatus;
+
+/*
+** A comparison code. Used for procedures that return comparision
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong.
+*/
+typedef enum _SECComparison {
+ SECLessThan = -1,
+ SECEqual = 0,
+ SECGreaterThan = 1
+} SECComparison;
+
+#endif /* _SECCOMMON_H_ */
diff --git a/lib/util/secder.h b/lib/util/secder.h
new file mode 100644
index 000000000..25fd3c972
--- /dev/null
+++ b/lib/util/secder.h
@@ -0,0 +1,176 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SECDER_H_
+#define _SECDER_H_
+
+#include "utilrename.h"
+
+/*
+ * secder.h - public data structures and prototypes for the DER encoding and
+ * decoding utilities library
+ *
+ * $Id$
+ */
+
+#include <time.h>
+
+#include "plarena.h"
+#include "prlong.h"
+
+#include "seccomon.h"
+#include "secdert.h"
+#include "prtime.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Encode a data structure into DER.
+** "dest" will be filled in (and memory allocated) to hold the der
+** encoded structure in "src"
+** "t" is a template structure which defines the shape of the
+** stored data
+** "src" is a pointer to the structure that will be encoded
+*/
+extern SECStatus DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *t,
+ void *src);
+
+extern SECStatus DER_Lengths(SECItem *item, int *header_len_p,
+ PRUint32 *contents_len_p);
+
+/*
+** Lower level der subroutine that stores the standard header into "to".
+** The header is of variable length, based on encodingLen.
+** The return value is the new value of "to" after skipping over the header.
+** "to" is where the header will be stored
+** "code" is the der code to write
+** "encodingLen" is the number of bytes of data that will follow
+** the header
+*/
+extern unsigned char *DER_StoreHeader(unsigned char *to, unsigned int code,
+ PRUint32 encodingLen);
+
+/*
+** Return the number of bytes it will take to hold a der encoded length.
+*/
+extern int DER_LengthLength(PRUint32 len);
+
+/*
+** Store a der encoded *signed* integer (whose value is "src") into "dst".
+** XXX This should really be enhanced to take a long.
+*/
+extern SECStatus DER_SetInteger(PLArenaPool *arena, SECItem *dst, PRInt32 src);
+
+/*
+** Store a der encoded *unsigned* integer (whose value is "src") into "dst".
+** XXX This should really be enhanced to take an unsigned long.
+*/
+extern SECStatus DER_SetUInteger(PLArenaPool *arena, SECItem *dst, PRUint32 src);
+
+/*
+** Decode a der encoded *signed* integer that is stored in "src".
+** If "-1" is returned, then the caller should check the error in
+** XP_GetError() to see if an overflow occurred (SEC_ERROR_BAD_DER).
+*/
+extern long DER_GetInteger(SECItem *src);
+
+/*
+** Decode a der encoded *unsigned* integer that is stored in "src".
+** If the ULONG_MAX is returned, then the caller should check the error
+** in XP_GetError() to see if an overflow occurred (SEC_ERROR_BAD_DER).
+*/
+extern unsigned long DER_GetUInteger(SECItem *src);
+
+/*
+** Convert an NSPR time value to a der encoded time value.
+** "result" is the der encoded time (memory is allocated)
+** "time" is the NSPR time value (Since Jan 1st, 1970).
+** time must be on or after January 1, 1950, and
+** before January 1, 2050
+** The caller is responsible for freeing up the buffer which
+** result->data points to upon a successful operation.
+*/
+extern SECStatus DER_TimeToUTCTime(SECItem *result, PRTime time);
+extern SECStatus DER_TimeToUTCTimeArena(PLArenaPool* arenaOpt,
+ SECItem *dst, PRTime gmttime);
+
+
+/*
+** Convert an ascii encoded time value (according to DER rules) into
+** an NSPR time value.
+** "result" the resulting NSPR time
+** "string" the der notation ascii value to decode
+*/
+extern SECStatus DER_AsciiToTime(PRTime *result, const char *string);
+
+/*
+** Same as DER_AsciiToTime except takes an SECItem instead of a string
+*/
+extern SECStatus DER_UTCTimeToTime(PRTime *result, const SECItem *time);
+
+/*
+** Convert a DER encoded UTC time to an ascii time representation
+** "utctime" is the DER encoded UTC time to be converted. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *DER_UTCTimeToAscii(SECItem *utcTime);
+
+/*
+** Convert a DER encoded UTC time to an ascii time representation, but only
+** include the day, not the time.
+** "utctime" is the DER encoded UTC time to be converted.
+** The caller is responsible for deallocating the returned buffer.
+*/
+extern char *DER_UTCDayToAscii(SECItem *utctime);
+/* same thing for DER encoded GeneralizedTime */
+extern char *DER_GeneralizedDayToAscii(SECItem *gentime);
+/* same thing for either DER UTCTime or GeneralizedTime */
+extern char *DER_TimeChoiceDayToAscii(SECItem *timechoice);
+
+/*
+** Convert a PRTime time to a DER encoded Generalized time
+** gmttime must be on or after January 1, year 1 and
+** before January 1, 10000.
+*/
+extern SECStatus DER_TimeToGeneralizedTime(SECItem *dst, PRTime gmttime);
+extern SECStatus DER_TimeToGeneralizedTimeArena(PLArenaPool* arenaOpt,
+ SECItem *dst, PRTime gmttime);
+
+/*
+** Convert a DER encoded Generalized time value into an NSPR time value.
+** "dst" the resulting NSPR time
+** "string" the der notation ascii value to decode
+*/
+extern SECStatus DER_GeneralizedTimeToTime(PRTime *dst, const SECItem *time);
+
+/*
+** Convert from a PRTime UTC time value to a formatted ascii value. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *CERT_UTCTime2FormattedAscii (PRTime utcTime, char *format);
+#define CERT_GeneralizedTime2FormattedAscii CERT_UTCTime2FormattedAscii
+
+/*
+** Convert from a PRTime Generalized time value to a formatted ascii value. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *CERT_GenTime2FormattedAscii (PRTime genTime, char *format);
+
+/*
+** decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME
+** or a SEC_ASN1_UTC_TIME
+*/
+
+extern SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input);
+
+/* encode a PRTime to an ASN.1 DER SECItem containing either a
+ SEC_ASN1_GENERALIZED_TIME or a SEC_ASN1_UTC_TIME */
+
+extern SECStatus DER_EncodeTimeChoice(PLArenaPool* arena, SECItem* output,
+ PRTime input);
+
+SEC_END_PROTOS
+
+#endif /* _SECDER_H_ */
+
diff --git a/lib/util/secdert.h b/lib/util/secdert.h
new file mode 100644
index 000000000..5e5976078
--- /dev/null
+++ b/lib/util/secdert.h
@@ -0,0 +1,131 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SECDERT_H_
+#define _SECDERT_H_
+/*
+ * secdert.h - public data structures for the DER encoding and
+ * decoding utilities library
+ *
+ * $Id$
+ */
+
+#include "utilrename.h"
+#include "seccomon.h"
+
+typedef struct DERTemplateStr DERTemplate;
+
+/*
+** An array of these structures defines an encoding for an object using DER.
+** The array usually starts with a dummy entry whose kind is DER_SEQUENCE;
+** such an array is terminated with an entry where kind == 0. (An array
+** which consists of a single component does not require a second dummy
+** entry -- the array is only searched as long as previous component(s)
+** instruct it.)
+*/
+struct DERTemplateStr {
+ /*
+ ** Kind of item being decoded/encoded, including tags and modifiers.
+ */
+ unsigned long kind;
+
+ /*
+ ** Offset from base of structure to field that holds the value
+ ** being decoded/encoded.
+ */
+ unsigned int offset;
+
+ /*
+ ** When kind suggests it (DER_POINTER, DER_INDEFINITE, DER_INLINE),
+ ** this points to a sub-template for nested encoding/decoding.
+ */
+ DERTemplate *sub;
+
+ /*
+ ** Argument value, dependent on "kind" and/or template placement
+ ** within an array of templates:
+ ** - In the first element of a template array, the value is the
+ ** size of the structure to allocate when this template is being
+ ** referenced by another template via DER_POINTER or DER_INDEFINITE.
+ ** - In a component of a DER_SET or DER_SEQUENCE which is *not* a
+ ** DER_UNIVERSAL type (that is, it has a class tag for either
+ ** DER_APPLICATION, DER_CONTEXT_SPECIFIC, or DER_PRIVATE), the
+ ** value is the underlying type of item being decoded/encoded.
+ */
+ unsigned long arg;
+};
+
+/************************************************************************/
+
+/* default chunksize for arenas used for DER stuff */
+#define DER_DEFAULT_CHUNKSIZE (2048)
+
+/*
+** BER/DER values for ASN.1 identifier octets.
+*/
+#define DER_TAG_MASK 0xff
+
+/*
+ * BER/DER universal type tag numbers.
+ * The values are defined by the X.208 standard; do not change them!
+ * NOTE: if you add anything to this list, you must add code to derdec.c
+ * to accept the tag, and probably also to derenc.c to encode it.
+ */
+#define DER_TAGNUM_MASK 0x1f
+#define DER_BOOLEAN 0x01
+#define DER_INTEGER 0x02
+#define DER_BIT_STRING 0x03
+#define DER_OCTET_STRING 0x04
+#define DER_NULL 0x05
+#define DER_OBJECT_ID 0x06
+#define DER_SEQUENCE 0x10
+#define DER_SET 0x11
+#define DER_PRINTABLE_STRING 0x13
+#define DER_T61_STRING 0x14
+#define DER_IA5_STRING 0x16
+#define DER_UTC_TIME 0x17
+#define DER_VISIBLE_STRING 0x1a
+#define DER_HIGH_TAG_NUMBER 0x1f
+
+/*
+** Modifiers to type tags. These are also specified by a/the
+** standard, and must not be changed.
+*/
+
+#define DER_METHOD_MASK 0x20
+#define DER_PRIMITIVE 0x00
+#define DER_CONSTRUCTED 0x20
+
+#define DER_CLASS_MASK 0xc0
+#define DER_UNIVERSAL 0x00
+#define DER_APPLICATION 0x40
+#define DER_CONTEXT_SPECIFIC 0x80
+#define DER_PRIVATE 0xc0
+
+/*
+** Our additions, used for templates.
+** These are not defined by any standard; the values are used internally only.
+** Just be careful to keep them out of the low 8 bits.
+*/
+#define DER_OPTIONAL 0x00100
+#define DER_EXPLICIT 0x00200
+#define DER_ANY 0x00400
+#define DER_INLINE 0x00800
+#define DER_POINTER 0x01000
+#define DER_INDEFINITE 0x02000
+#define DER_DERPTR 0x04000
+#define DER_SKIP 0x08000
+#define DER_FORCE 0x10000
+#define DER_OUTER 0x40000 /* for DER_DERPTR */
+
+/*
+** Macro to convert der decoded bit string into a decoded octet
+** string. All it needs to do is fiddle with the length code.
+*/
+#define DER_ConvertBitString(item) \
+{ \
+ (item)->len = ((item)->len + 7) >> 3; \
+}
+
+#endif /* _SECDERT_H_ */
diff --git a/lib/util/secdig.c b/lib/util/secdig.c
new file mode 100644
index 000000000..530c520d0
--- /dev/null
+++ b/lib/util/secdig.c
@@ -0,0 +1,181 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* $Id$ */
+#include "secdig.h"
+
+#include "secoid.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+/*
+ * XXX Want to have a SGN_DecodeDigestInfo, like:
+ * SGNDigestInfo *SGN_DecodeDigestInfo(SECItem *didata);
+ * that creates a pool and allocates from it and decodes didata into
+ * the newly allocated DigestInfo structure. Then fix secvfy.c (it
+ * will no longer need an arena itself) to call this and then call
+ * DestroyDigestInfo when it is done, then can remove the old template
+ * above and keep our new template static and "hidden".
+ */
+
+/*
+ * XXX It might be nice to combine the following two functions (create
+ * and encode). I think that is all anybody ever wants to do anyway.
+ */
+
+SECItem *
+SGN_EncodeDigestInfo(PRArenaPool *poolp, SECItem *dest, SGNDigestInfo *diginfo)
+{
+ return SEC_ASN1EncodeItem (poolp, dest, diginfo, sgn_DigestInfoTemplate);
+}
+
+SGNDigestInfo *
+SGN_CreateDigestInfo(SECOidTag algorithm, unsigned char *sig, unsigned len)
+{
+ SGNDigestInfo *di;
+ SECStatus rv;
+ PRArenaPool *arena;
+ SECItem *null_param;
+ SECItem dummy_value;
+
+ switch (algorithm) {
+ case SEC_OID_MD2:
+ case SEC_OID_MD5:
+ case SEC_OID_SHA1:
+ case SEC_OID_SHA224:
+ case SEC_OID_SHA256:
+ case SEC_OID_SHA384:
+ case SEC_OID_SHA512:
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return NULL;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ return NULL;
+ }
+
+ di = (SGNDigestInfo *) PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
+ if (di == NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ return NULL;
+ }
+
+ di->arena = arena;
+
+ /*
+ * PKCS #1 specifies that the AlgorithmID must have a NULL parameter
+ * (as opposed to no parameter at all).
+ */
+ dummy_value.data = NULL;
+ dummy_value.len = 0;
+ null_param = SEC_ASN1EncodeItem(NULL, NULL, &dummy_value, SEC_NullTemplate);
+ if (null_param == NULL) {
+ goto loser;
+ }
+
+ rv = SECOID_SetAlgorithmID(arena, &di->digestAlgorithm, algorithm,
+ null_param);
+
+ SECITEM_FreeItem(null_param, PR_TRUE);
+
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ di->digest.data = (unsigned char *) PORT_ArenaAlloc(arena, len);
+ if (di->digest.data == NULL) {
+ goto loser;
+ }
+
+ di->digest.len = len;
+ PORT_Memcpy(di->digest.data, sig, len);
+ return di;
+
+ loser:
+ SGN_DestroyDigestInfo(di);
+ return NULL;
+}
+
+SGNDigestInfo *
+SGN_DecodeDigestInfo(SECItem *didata)
+{
+ PRArenaPool *arena;
+ SGNDigestInfo *di;
+ SECStatus rv = SECFailure;
+ SECItem diCopy = {siBuffer, NULL, 0};
+
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if(arena == NULL)
+ return NULL;
+
+ rv = SECITEM_CopyItem(arena, &diCopy, didata);
+ if (rv != SECSuccess) {
+ PORT_FreeArena(arena, PR_FALSE);
+ return NULL;
+ }
+
+ di = (SGNDigestInfo *)PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
+ if (di != NULL) {
+ di->arena = arena;
+ rv = SEC_QuickDERDecodeItem(arena, di, sgn_DigestInfoTemplate, &diCopy);
+ }
+
+ if ((di == NULL) || (rv != SECSuccess)) {
+ PORT_FreeArena(arena, PR_FALSE);
+ di = NULL;
+ }
+
+ return di;
+}
+
+void
+SGN_DestroyDigestInfo(SGNDigestInfo *di)
+{
+ if (di && di->arena) {
+ PORT_FreeArena(di->arena, PR_FALSE);
+ }
+
+ return;
+}
+
+SECStatus
+SGN_CopyDigestInfo(PRArenaPool *poolp, SGNDigestInfo *a, SGNDigestInfo *b)
+{
+ SECStatus rv;
+ void *mark;
+
+ if((poolp == NULL) || (a == NULL) || (b == NULL))
+ return SECFailure;
+
+ mark = PORT_ArenaMark(poolp);
+ a->arena = poolp;
+ rv = SECOID_CopyAlgorithmID(poolp, &a->digestAlgorithm,
+ &b->digestAlgorithm);
+ if (rv == SECSuccess)
+ rv = SECITEM_CopyItem(poolp, &a->digest, &b->digest);
+
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease(poolp, mark);
+ } else {
+ PORT_ArenaUnmark(poolp, mark);
+ }
+
+ return rv;
+}
+
+SECComparison
+SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b)
+{
+ SECComparison rv;
+
+ /* Check signature algorithm's */
+ rv = SECOID_CompareAlgorithmID(&a->digestAlgorithm, &b->digestAlgorithm);
+ if (rv) return rv;
+
+ /* Compare signature block length's */
+ rv = SECITEM_CompareItem(&a->digest, &b->digest);
+ return rv;
+}
diff --git a/lib/util/secdig.h b/lib/util/secdig.h
new file mode 100644
index 000000000..f01c543d9
--- /dev/null
+++ b/lib/util/secdig.h
@@ -0,0 +1,104 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* $Id$ */
+
+#ifndef _SECDIG_H_
+#define _SECDIG_H_
+
+#include "utilrename.h"
+#include "secdigt.h"
+
+#include "seccomon.h"
+#include "secasn1t.h"
+#include "secdert.h"
+
+SEC_BEGIN_PROTOS
+
+
+extern const SEC_ASN1Template sgn_DigestInfoTemplate[];
+
+SEC_ASN1_CHOOSER_DECLARE(sgn_DigestInfoTemplate)
+
+/****************************************/
+/*
+** Digest-info functions
+*/
+
+/*
+** Create a new digest-info object
+** "algorithm" one of SEC_OID_MD2, SEC_OID_MD5, or SEC_OID_SHA1
+** "sig" the raw signature data (from MD2 or MD5)
+** "sigLen" the length of the signature data
+**
+** NOTE: this is a low level routine used to prepare some data for PKCS#1
+** digital signature formatting.
+**
+** XXX It might be nice to combine the create and encode functions.
+** I think that is all anybody ever wants to do anyway.
+*/
+extern SGNDigestInfo *SGN_CreateDigestInfo(SECOidTag algorithm,
+ unsigned char *sig,
+ unsigned int sigLen);
+
+/*
+** Destroy a digest-info object
+*/
+extern void SGN_DestroyDigestInfo(SGNDigestInfo *info);
+
+/*
+** Encode a digest-info object
+** "poolp" is where to allocate the result from; it can be NULL in
+** which case generic heap allocation (XP_ALLOC) will be used
+** "dest" is where to store the result; it can be NULL, in which case
+** it will be allocated (from poolp or heap, as explained above)
+** "diginfo" is the object to be encoded
+** The return value is NULL if any error occurred, otherwise it is the
+** resulting SECItem (either allocated or the same as the "dest" parameter).
+**
+** XXX It might be nice to combine the create and encode functions.
+** I think that is all anybody ever wants to do anyway.
+*/
+extern SECItem *SGN_EncodeDigestInfo(PLArenaPool *poolp, SECItem *dest,
+ SGNDigestInfo *diginfo);
+
+/*
+** Decode a DER encoded digest info objct.
+** didata is thr source of the encoded digest.
+** The return value is NULL if an error occurs. Otherwise, a
+** digest info object which is allocated within it's own
+** pool is returned. The digest info should be deleted
+** by later calling SGN_DestroyDigestInfo.
+*/
+extern SGNDigestInfo *SGN_DecodeDigestInfo(SECItem *didata);
+
+
+/*
+** Copy digest info.
+** poolp is the arena to which the digest will be copied.
+** a is the destination digest, it must be non-NULL.
+** b is the source digest
+** This function is for copying digests. It allows digests
+** to be copied into a specified pool. If the digest is in
+** the same pool as other data, you do not want to delete
+** the digest by calling SGN_DestroyDigestInfo.
+** A return value of SECFailure indicates an error. A return
+** of SECSuccess indicates no error occurred.
+*/
+extern SECStatus SGN_CopyDigestInfo(PLArenaPool *poolp,
+ SGNDigestInfo *a,
+ SGNDigestInfo *b);
+
+/*
+** Compare two digest-info objects, returning the difference between
+** them.
+*/
+extern SECComparison SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b);
+
+
+SEC_END_PROTOS
+
+#endif /* _SECDIG_H_ */
diff --git a/lib/util/secdigt.h b/lib/util/secdigt.h
new file mode 100644
index 000000000..5729dcc85
--- /dev/null
+++ b/lib/util/secdigt.h
@@ -0,0 +1,29 @@
+/*
+ * secdigt.h - public data structures for digestinfos from the util lib.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* $Id$ */
+
+#ifndef _SECDIGT_H_
+#define _SECDIGT_H_
+
+#include "utilrename.h"
+#include "plarena.h"
+#include "secoidt.h"
+#include "secitem.h"
+
+/*
+** A PKCS#1 digest-info object
+*/
+struct SGNDigestInfoStr {
+ PLArenaPool * arena;
+ SECAlgorithmID digestAlgorithm;
+ SECItem digest;
+};
+typedef struct SGNDigestInfoStr SGNDigestInfo;
+
+
+
+#endif /* _SECDIGT_H_ */
diff --git a/lib/util/secerr.h b/lib/util/secerr.h
new file mode 100644
index 000000000..490dabaf4
--- /dev/null
+++ b/lib/util/secerr.h
@@ -0,0 +1,218 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __SEC_ERR_H_
+#define __SEC_ERR_H_
+
+#include "utilrename.h"
+
+#define SEC_ERROR_BASE (-0x2000)
+#define SEC_ERROR_LIMIT (SEC_ERROR_BASE + 1000)
+
+#define IS_SEC_ERROR(code) \
+ (((code) >= SEC_ERROR_BASE) && ((code) < SEC_ERROR_LIMIT))
+
+#ifndef NO_SECURITY_ERROR_ENUM
+typedef enum {
+SEC_ERROR_IO = SEC_ERROR_BASE + 0,
+SEC_ERROR_LIBRARY_FAILURE = SEC_ERROR_BASE + 1,
+SEC_ERROR_BAD_DATA = SEC_ERROR_BASE + 2,
+SEC_ERROR_OUTPUT_LEN = SEC_ERROR_BASE + 3,
+SEC_ERROR_INPUT_LEN = SEC_ERROR_BASE + 4,
+SEC_ERROR_INVALID_ARGS = SEC_ERROR_BASE + 5,
+SEC_ERROR_INVALID_ALGORITHM = SEC_ERROR_BASE + 6,
+SEC_ERROR_INVALID_AVA = SEC_ERROR_BASE + 7,
+SEC_ERROR_INVALID_TIME = SEC_ERROR_BASE + 8,
+SEC_ERROR_BAD_DER = SEC_ERROR_BASE + 9,
+SEC_ERROR_BAD_SIGNATURE = SEC_ERROR_BASE + 10,
+SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11,
+SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12,
+SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13,
+SEC_ERROR_BAD_KEY = SEC_ERROR_BASE + 14,
+SEC_ERROR_BAD_PASSWORD = SEC_ERROR_BASE + 15,
+SEC_ERROR_RETRY_PASSWORD = SEC_ERROR_BASE + 16,
+SEC_ERROR_NO_NODELOCK = SEC_ERROR_BASE + 17,
+SEC_ERROR_BAD_DATABASE = SEC_ERROR_BASE + 18,
+SEC_ERROR_NO_MEMORY = SEC_ERROR_BASE + 19,
+SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20,
+SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21,
+SEC_ERROR_DUPLICATE_CERT = (SEC_ERROR_BASE + 22),
+SEC_ERROR_DUPLICATE_CERT_NAME = (SEC_ERROR_BASE + 23),
+SEC_ERROR_ADDING_CERT = (SEC_ERROR_BASE + 24),
+SEC_ERROR_FILING_KEY = (SEC_ERROR_BASE + 25),
+SEC_ERROR_NO_KEY = (SEC_ERROR_BASE + 26),
+SEC_ERROR_CERT_VALID = (SEC_ERROR_BASE + 27),
+SEC_ERROR_CERT_NOT_VALID = (SEC_ERROR_BASE + 28),
+SEC_ERROR_CERT_NO_RESPONSE = (SEC_ERROR_BASE + 29),
+SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = (SEC_ERROR_BASE + 30),
+SEC_ERROR_CRL_EXPIRED = (SEC_ERROR_BASE + 31),
+SEC_ERROR_CRL_BAD_SIGNATURE = (SEC_ERROR_BASE + 32),
+SEC_ERROR_CRL_INVALID = (SEC_ERROR_BASE + 33),
+SEC_ERROR_EXTENSION_VALUE_INVALID = (SEC_ERROR_BASE + 34),
+SEC_ERROR_EXTENSION_NOT_FOUND = (SEC_ERROR_BASE + 35),
+SEC_ERROR_CA_CERT_INVALID = (SEC_ERROR_BASE + 36),
+SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID = (SEC_ERROR_BASE + 37),
+SEC_ERROR_CERT_USAGES_INVALID = (SEC_ERROR_BASE + 38),
+SEC_INTERNAL_ONLY = (SEC_ERROR_BASE + 39),
+SEC_ERROR_INVALID_KEY = (SEC_ERROR_BASE + 40),
+SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 41),
+SEC_ERROR_OLD_CRL = (SEC_ERROR_BASE + 42),
+SEC_ERROR_NO_EMAIL_CERT = (SEC_ERROR_BASE + 43),
+SEC_ERROR_NO_RECIPIENT_CERTS_QUERY = (SEC_ERROR_BASE + 44),
+SEC_ERROR_NOT_A_RECIPIENT = (SEC_ERROR_BASE + 45),
+SEC_ERROR_PKCS7_KEYALG_MISMATCH = (SEC_ERROR_BASE + 46),
+SEC_ERROR_PKCS7_BAD_SIGNATURE = (SEC_ERROR_BASE + 47),
+SEC_ERROR_UNSUPPORTED_KEYALG = (SEC_ERROR_BASE + 48),
+SEC_ERROR_DECRYPTION_DISALLOWED = (SEC_ERROR_BASE + 49),
+/* Fortezza Alerts */
+XP_SEC_FORTEZZA_BAD_CARD = (SEC_ERROR_BASE + 50),
+XP_SEC_FORTEZZA_NO_CARD = (SEC_ERROR_BASE + 51),
+XP_SEC_FORTEZZA_NONE_SELECTED = (SEC_ERROR_BASE + 52),
+XP_SEC_FORTEZZA_MORE_INFO = (SEC_ERROR_BASE + 53),
+XP_SEC_FORTEZZA_PERSON_NOT_FOUND = (SEC_ERROR_BASE + 54),
+XP_SEC_FORTEZZA_NO_MORE_INFO = (SEC_ERROR_BASE + 55),
+XP_SEC_FORTEZZA_BAD_PIN = (SEC_ERROR_BASE + 56),
+XP_SEC_FORTEZZA_PERSON_ERROR = (SEC_ERROR_BASE + 57),
+SEC_ERROR_NO_KRL = (SEC_ERROR_BASE + 58),
+SEC_ERROR_KRL_EXPIRED = (SEC_ERROR_BASE + 59),
+SEC_ERROR_KRL_BAD_SIGNATURE = (SEC_ERROR_BASE + 60),
+SEC_ERROR_REVOKED_KEY = (SEC_ERROR_BASE + 61),
+SEC_ERROR_KRL_INVALID = (SEC_ERROR_BASE + 62),
+SEC_ERROR_NEED_RANDOM = (SEC_ERROR_BASE + 63),
+SEC_ERROR_NO_MODULE = (SEC_ERROR_BASE + 64),
+SEC_ERROR_NO_TOKEN = (SEC_ERROR_BASE + 65),
+SEC_ERROR_READ_ONLY = (SEC_ERROR_BASE + 66),
+SEC_ERROR_NO_SLOT_SELECTED = (SEC_ERROR_BASE + 67),
+SEC_ERROR_CERT_NICKNAME_COLLISION = (SEC_ERROR_BASE + 68),
+SEC_ERROR_KEY_NICKNAME_COLLISION = (SEC_ERROR_BASE + 69),
+SEC_ERROR_SAFE_NOT_CREATED = (SEC_ERROR_BASE + 70),
+SEC_ERROR_BAGGAGE_NOT_CREATED = (SEC_ERROR_BASE + 71),
+XP_JAVA_REMOVE_PRINCIPAL_ERROR = (SEC_ERROR_BASE + 72),
+XP_JAVA_DELETE_PRIVILEGE_ERROR = (SEC_ERROR_BASE + 73),
+XP_JAVA_CERT_NOT_EXISTS_ERROR = (SEC_ERROR_BASE + 74),
+SEC_ERROR_BAD_EXPORT_ALGORITHM = (SEC_ERROR_BASE + 75),
+SEC_ERROR_EXPORTING_CERTIFICATES = (SEC_ERROR_BASE + 76),
+SEC_ERROR_IMPORTING_CERTIFICATES = (SEC_ERROR_BASE + 77),
+SEC_ERROR_PKCS12_DECODING_PFX = (SEC_ERROR_BASE + 78),
+SEC_ERROR_PKCS12_INVALID_MAC = (SEC_ERROR_BASE + 79),
+SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM = (SEC_ERROR_BASE + 80),
+SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE = (SEC_ERROR_BASE + 81),
+SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE = (SEC_ERROR_BASE + 82),
+SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM = (SEC_ERROR_BASE + 83),
+SEC_ERROR_PKCS12_UNSUPPORTED_VERSION = (SEC_ERROR_BASE + 84),
+SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT = (SEC_ERROR_BASE + 85),
+SEC_ERROR_PKCS12_CERT_COLLISION = (SEC_ERROR_BASE + 86),
+SEC_ERROR_USER_CANCELLED = (SEC_ERROR_BASE + 87),
+SEC_ERROR_PKCS12_DUPLICATE_DATA = (SEC_ERROR_BASE + 88),
+SEC_ERROR_MESSAGE_SEND_ABORTED = (SEC_ERROR_BASE + 89),
+SEC_ERROR_INADEQUATE_KEY_USAGE = (SEC_ERROR_BASE + 90),
+SEC_ERROR_INADEQUATE_CERT_TYPE = (SEC_ERROR_BASE + 91),
+SEC_ERROR_CERT_ADDR_MISMATCH = (SEC_ERROR_BASE + 92),
+SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY = (SEC_ERROR_BASE + 93),
+SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN = (SEC_ERROR_BASE + 94),
+SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME = (SEC_ERROR_BASE + 95),
+SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY = (SEC_ERROR_BASE + 96),
+SEC_ERROR_PKCS12_UNABLE_TO_WRITE = (SEC_ERROR_BASE + 97),
+SEC_ERROR_PKCS12_UNABLE_TO_READ = (SEC_ERROR_BASE + 98),
+SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED = (SEC_ERROR_BASE + 99),
+SEC_ERROR_KEYGEN_FAIL = (SEC_ERROR_BASE + 100),
+SEC_ERROR_INVALID_PASSWORD = (SEC_ERROR_BASE + 101),
+SEC_ERROR_RETRY_OLD_PASSWORD = (SEC_ERROR_BASE + 102),
+SEC_ERROR_BAD_NICKNAME = (SEC_ERROR_BASE + 103),
+SEC_ERROR_NOT_FORTEZZA_ISSUER = (SEC_ERROR_BASE + 104),
+SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY = (SEC_ERROR_BASE + 105),
+SEC_ERROR_JS_INVALID_MODULE_NAME = (SEC_ERROR_BASE + 106),
+SEC_ERROR_JS_INVALID_DLL = (SEC_ERROR_BASE + 107),
+SEC_ERROR_JS_ADD_MOD_FAILURE = (SEC_ERROR_BASE + 108),
+SEC_ERROR_JS_DEL_MOD_FAILURE = (SEC_ERROR_BASE + 109),
+SEC_ERROR_OLD_KRL = (SEC_ERROR_BASE + 110),
+SEC_ERROR_CKL_CONFLICT = (SEC_ERROR_BASE + 111),
+SEC_ERROR_CERT_NOT_IN_NAME_SPACE = (SEC_ERROR_BASE + 112),
+SEC_ERROR_KRL_NOT_YET_VALID = (SEC_ERROR_BASE + 113),
+SEC_ERROR_CRL_NOT_YET_VALID = (SEC_ERROR_BASE + 114),
+SEC_ERROR_UNKNOWN_CERT = (SEC_ERROR_BASE + 115),
+SEC_ERROR_UNKNOWN_SIGNER = (SEC_ERROR_BASE + 116),
+SEC_ERROR_CERT_BAD_ACCESS_LOCATION = (SEC_ERROR_BASE + 117),
+SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE = (SEC_ERROR_BASE + 118),
+SEC_ERROR_OCSP_BAD_HTTP_RESPONSE = (SEC_ERROR_BASE + 119),
+SEC_ERROR_OCSP_MALFORMED_REQUEST = (SEC_ERROR_BASE + 120),
+SEC_ERROR_OCSP_SERVER_ERROR = (SEC_ERROR_BASE + 121),
+SEC_ERROR_OCSP_TRY_SERVER_LATER = (SEC_ERROR_BASE + 122),
+SEC_ERROR_OCSP_REQUEST_NEEDS_SIG = (SEC_ERROR_BASE + 123),
+SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST = (SEC_ERROR_BASE + 124),
+SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS = (SEC_ERROR_BASE + 125),
+SEC_ERROR_OCSP_UNKNOWN_CERT = (SEC_ERROR_BASE + 126),
+SEC_ERROR_OCSP_NOT_ENABLED = (SEC_ERROR_BASE + 127),
+SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER = (SEC_ERROR_BASE + 128),
+SEC_ERROR_OCSP_MALFORMED_RESPONSE = (SEC_ERROR_BASE + 129),
+SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE = (SEC_ERROR_BASE + 130),
+SEC_ERROR_OCSP_FUTURE_RESPONSE = (SEC_ERROR_BASE + 131),
+SEC_ERROR_OCSP_OLD_RESPONSE = (SEC_ERROR_BASE + 132),
+/* smime stuff */
+SEC_ERROR_DIGEST_NOT_FOUND = (SEC_ERROR_BASE + 133),
+SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE = (SEC_ERROR_BASE + 134),
+SEC_ERROR_MODULE_STUCK = (SEC_ERROR_BASE + 135),
+SEC_ERROR_BAD_TEMPLATE = (SEC_ERROR_BASE + 136),
+SEC_ERROR_CRL_NOT_FOUND = (SEC_ERROR_BASE + 137),
+SEC_ERROR_REUSED_ISSUER_AND_SERIAL = (SEC_ERROR_BASE + 138),
+SEC_ERROR_BUSY = (SEC_ERROR_BASE + 139),
+SEC_ERROR_EXTRA_INPUT = (SEC_ERROR_BASE + 140),
+/* error codes used by elliptic curve code */
+SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE = (SEC_ERROR_BASE + 141),
+SEC_ERROR_UNSUPPORTED_EC_POINT_FORM = (SEC_ERROR_BASE + 142),
+SEC_ERROR_UNRECOGNIZED_OID = (SEC_ERROR_BASE + 143),
+SEC_ERROR_OCSP_INVALID_SIGNING_CERT = (SEC_ERROR_BASE + 144),
+/* new revocation errors */
+SEC_ERROR_REVOKED_CERTIFICATE_CRL = (SEC_ERROR_BASE + 145),
+SEC_ERROR_REVOKED_CERTIFICATE_OCSP = (SEC_ERROR_BASE + 146),
+SEC_ERROR_CRL_INVALID_VERSION = (SEC_ERROR_BASE + 147),
+SEC_ERROR_CRL_V1_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 148),
+SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 149),
+SEC_ERROR_UNKNOWN_OBJECT_TYPE = (SEC_ERROR_BASE + 150),
+SEC_ERROR_INCOMPATIBLE_PKCS11 = (SEC_ERROR_BASE + 151),
+SEC_ERROR_NO_EVENT = (SEC_ERROR_BASE + 152),
+SEC_ERROR_CRL_ALREADY_EXISTS = (SEC_ERROR_BASE + 153),
+SEC_ERROR_NOT_INITIALIZED = (SEC_ERROR_BASE + 154),
+SEC_ERROR_TOKEN_NOT_LOGGED_IN = (SEC_ERROR_BASE + 155),
+SEC_ERROR_OCSP_RESPONDER_CERT_INVALID = (SEC_ERROR_BASE + 156),
+SEC_ERROR_OCSP_BAD_SIGNATURE = (SEC_ERROR_BASE + 157),
+
+SEC_ERROR_OUT_OF_SEARCH_LIMITS = (SEC_ERROR_BASE + 158),
+SEC_ERROR_INVALID_POLICY_MAPPING = (SEC_ERROR_BASE + 159),
+SEC_ERROR_POLICY_VALIDATION_FAILED = (SEC_ERROR_BASE + 160),
+/* No longer used. Unknown AIA location types are now silently ignored. */
+SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE = (SEC_ERROR_BASE + 161),
+SEC_ERROR_BAD_HTTP_RESPONSE = (SEC_ERROR_BASE + 162),
+SEC_ERROR_BAD_LDAP_RESPONSE = (SEC_ERROR_BASE + 163),
+SEC_ERROR_FAILED_TO_ENCODE_DATA = (SEC_ERROR_BASE + 164),
+SEC_ERROR_BAD_INFO_ACCESS_LOCATION = (SEC_ERROR_BASE + 165),
+
+SEC_ERROR_LIBPKIX_INTERNAL = (SEC_ERROR_BASE + 166),
+
+SEC_ERROR_PKCS11_GENERAL_ERROR = (SEC_ERROR_BASE + 167),
+SEC_ERROR_PKCS11_FUNCTION_FAILED = (SEC_ERROR_BASE + 168),
+SEC_ERROR_PKCS11_DEVICE_ERROR = (SEC_ERROR_BASE + 169),
+
+SEC_ERROR_BAD_INFO_ACCESS_METHOD = (SEC_ERROR_BASE + 170),
+SEC_ERROR_CRL_IMPORT_FAILED = (SEC_ERROR_BASE + 171),
+
+SEC_ERROR_EXPIRED_PASSWORD = (SEC_ERROR_BASE + 172),
+SEC_ERROR_LOCKED_PASSWORD = (SEC_ERROR_BASE + 173),
+
+SEC_ERROR_UNKNOWN_PKCS11_ERROR = (SEC_ERROR_BASE + 174),
+
+SEC_ERROR_BAD_CRL_DP_URL = (SEC_ERROR_BASE + 175),
+
+SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = (SEC_ERROR_BASE + 176),
+
+SEC_ERROR_LEGACY_DATABASE = (SEC_ERROR_BASE + 177),
+
+SEC_ERROR_APPLICATION_CALLBACK_ERROR = (SEC_ERROR_BASE + 178),
+
+/* Add new error codes above here. */
+SEC_ERROR_END_OF_LIST
+} SECErrorCodes;
+#endif /* NO_SECURITY_ERROR_ENUM */
+
+#endif /* __SEC_ERR_H_ */
diff --git a/lib/util/secitem.c b/lib/util/secitem.c
new file mode 100644
index 000000000..f03fb2c7a
--- /dev/null
+++ b/lib/util/secitem.c
@@ -0,0 +1,419 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Support routines for SECItem data structure.
+ *
+ * $Id$
+ */
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "base64.h"
+#include "secerr.h"
+#include "secport.h"
+
+SECItem *
+SECITEM_AllocItem(PRArenaPool *arena, SECItem *item, unsigned int len)
+{
+ SECItem *result = NULL;
+ void *mark = NULL;
+
+ if (arena != NULL) {
+ mark = PORT_ArenaMark(arena);
+ }
+
+ if (item == NULL) {
+ if (arena != NULL) {
+ result = PORT_ArenaZAlloc(arena, sizeof(SECItem));
+ } else {
+ result = PORT_ZAlloc(sizeof(SECItem));
+ }
+ if (result == NULL) {
+ goto loser;
+ }
+ } else {
+ PORT_Assert(item->data == NULL);
+ result = item;
+ }
+
+ result->len = len;
+ if (len) {
+ if (arena != NULL) {
+ result->data = PORT_ArenaAlloc(arena, len);
+ } else {
+ result->data = PORT_Alloc(len);
+ }
+ if (result->data == NULL) {
+ goto loser;
+ }
+ } else {
+ result->data = NULL;
+ }
+
+ if (mark) {
+ PORT_ArenaUnmark(arena, mark);
+ }
+ return(result);
+
+loser:
+ if ( arena != NULL ) {
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ if (item != NULL) {
+ item->data = NULL;
+ item->len = 0;
+ }
+ } else {
+ if (result != NULL) {
+ SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
+ }
+ /*
+ * If item is not NULL, the above has set item->data and
+ * item->len to 0.
+ */
+ }
+ return(NULL);
+}
+
+SECStatus
+SECITEM_ReallocItem(PRArenaPool *arena, SECItem *item, unsigned int oldlen,
+ unsigned int newlen)
+{
+ PORT_Assert(item != NULL);
+ if (item == NULL) {
+ /* XXX Set error. But to what? */
+ return SECFailure;
+ }
+
+ /*
+ * If no old length, degenerate to just plain alloc.
+ */
+ if (oldlen == 0) {
+ PORT_Assert(item->data == NULL || item->len == 0);
+ if (newlen == 0) {
+ /* Nothing to do. Weird, but not a failure. */
+ return SECSuccess;
+ }
+ item->len = newlen;
+ if (arena != NULL) {
+ item->data = PORT_ArenaAlloc(arena, newlen);
+ } else {
+ item->data = PORT_Alloc(newlen);
+ }
+ } else {
+ if (arena != NULL) {
+ item->data = PORT_ArenaGrow(arena, item->data, oldlen, newlen);
+ } else {
+ item->data = PORT_Realloc(item->data, newlen);
+ }
+ }
+
+ if (item->data == NULL) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECComparison
+SECITEM_CompareItem(const SECItem *a, const SECItem *b)
+{
+ unsigned m;
+ int rv;
+
+ if (a == b)
+ return SECEqual;
+ if (!a || !a->len || !a->data)
+ return (!b || !b->len || !b->data) ? SECEqual : SECLessThan;
+ if (!b || !b->len || !b->data)
+ return SECGreaterThan;
+
+ m = ( ( a->len < b->len ) ? a->len : b->len );
+
+ rv = PORT_Memcmp(a->data, b->data, m);
+ if (rv) {
+ return rv < 0 ? SECLessThan : SECGreaterThan;
+ }
+ if (a->len < b->len) {
+ return SECLessThan;
+ }
+ if (a->len == b->len) {
+ return SECEqual;
+ }
+ return SECGreaterThan;
+}
+
+PRBool
+SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
+{
+ if (a->len != b->len)
+ return PR_FALSE;
+ if (!a->len)
+ return PR_TRUE;
+ if (!a->data || !b->data) {
+ /* avoid null pointer crash. */
+ return (PRBool)(a->data == b->data);
+ }
+ return (PRBool)!PORT_Memcmp(a->data, b->data, a->len);
+}
+
+SECItem *
+SECITEM_DupItem(const SECItem *from)
+{
+ return SECITEM_ArenaDupItem(NULL, from);
+}
+
+SECItem *
+SECITEM_ArenaDupItem(PRArenaPool *arena, const SECItem *from)
+{
+ SECItem *to;
+
+ if ( from == NULL ) {
+ return(NULL);
+ }
+
+ if ( arena != NULL ) {
+ to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
+ } else {
+ to = (SECItem *)PORT_Alloc(sizeof(SECItem));
+ }
+ if ( to == NULL ) {
+ return(NULL);
+ }
+
+ if ( arena != NULL ) {
+ to->data = (unsigned char *)PORT_ArenaAlloc(arena, from->len);
+ } else {
+ to->data = (unsigned char *)PORT_Alloc(from->len);
+ }
+ if ( to->data == NULL ) {
+ PORT_Free(to);
+ return(NULL);
+ }
+
+ to->len = from->len;
+ to->type = from->type;
+ if ( to->len ) {
+ PORT_Memcpy(to->data, from->data, to->len);
+ }
+
+ return(to);
+}
+
+SECStatus
+SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, const SECItem *from)
+{
+ to->type = from->type;
+ if (from->data && from->len) {
+ if ( arena ) {
+ to->data = (unsigned char*) PORT_ArenaAlloc(arena, from->len);
+ } else {
+ to->data = (unsigned char*) PORT_Alloc(from->len);
+ }
+
+ if (!to->data) {
+ return SECFailure;
+ }
+ PORT_Memcpy(to->data, from->data, from->len);
+ to->len = from->len;
+ } else {
+ /*
+ * If from->data is NULL but from->len is nonzero, this function
+ * will succeed. Is this right?
+ */
+ to->data = 0;
+ to->len = 0;
+ }
+ return SECSuccess;
+}
+
+void
+SECITEM_FreeItem(SECItem *zap, PRBool freeit)
+{
+ if (zap) {
+ PORT_Free(zap->data);
+ zap->data = 0;
+ zap->len = 0;
+ if (freeit) {
+ PORT_Free(zap);
+ }
+ }
+}
+
+void
+SECITEM_ZfreeItem(SECItem *zap, PRBool freeit)
+{
+ if (zap) {
+ PORT_ZFree(zap->data, zap->len);
+ zap->data = 0;
+ zap->len = 0;
+ if (freeit) {
+ PORT_ZFree(zap, sizeof(SECItem));
+ }
+ }
+}
+/* these reroutines were taken from pkix oid.c, which is supposed to
+ * replace this file some day */
+/*
+ * This is the hash function. We simply XOR the encoded form with
+ * itself in sizeof(PLHashNumber)-byte chunks. Improving this
+ * routine is left as an excercise for the more mathematically
+ * inclined student.
+ */
+PLHashNumber PR_CALLBACK
+SECITEM_Hash ( const void *key)
+{
+ const SECItem *item = (const SECItem *)key;
+ PLHashNumber rv = 0;
+
+ PRUint8 *data = (PRUint8 *)item->data;
+ PRUint32 i;
+ PRUint8 *rvc = (PRUint8 *)&rv;
+
+ for( i = 0; i < item->len; i++ ) {
+ rvc[ i % sizeof(rv) ] ^= *data;
+ data++;
+ }
+
+ return rv;
+}
+
+/*
+ * This is the key-compare function. It simply does a lexical
+ * comparison on the item data. This does not result in
+ * quite the same ordering as the "sequence of numbers" order,
+ * but heck it's only used internally by the hash table anyway.
+ */
+PRIntn PR_CALLBACK
+SECITEM_HashCompare ( const void *k1, const void *k2)
+{
+ const SECItem *i1 = (const SECItem *)k1;
+ const SECItem *i2 = (const SECItem *)k2;
+
+ return SECITEM_ItemsAreEqual(i1,i2);
+}
+
+SECItemArray *
+SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len)
+{
+ SECItemArray *result = NULL;
+ void *mark = NULL;
+
+ if (arena != NULL) {
+ mark = PORT_ArenaMark(arena);
+ }
+
+ if (array == NULL) {
+ if (arena != NULL) {
+ result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray));
+ } else {
+ result = PORT_ZAlloc(sizeof(SECItemArray));
+ }
+ if (result == NULL) {
+ goto loser;
+ }
+ } else {
+ PORT_Assert(array->items == NULL);
+ result = array;
+ }
+
+ result->len = len;
+ if (len) {
+ if (arena != NULL) {
+ result->items = PORT_ArenaZNewArray(arena, SECItem, len);
+ } else {
+ result->items = PORT_ZNewArray(SECItem, len);
+ }
+ if (result->items == NULL) {
+ goto loser;
+ }
+ } else {
+ result->items = NULL;
+ }
+
+ if (mark) {
+ PORT_ArenaUnmark(arena, mark);
+ }
+ return(result);
+
+loser:
+ if ( arena != NULL ) {
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ if (array != NULL) {
+ array->items = NULL;
+ array->len = 0;
+ }
+ } else {
+ if (result != NULL && array == NULL) {
+ PORT_Free(result);
+ }
+ /*
+ * If array is not NULL, the above has set array->data and
+ * array->len to 0.
+ */
+ }
+ return(NULL);
+}
+
+void secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit)
+{
+ unsigned int i;
+
+ if (!array || !array->len || !array->items)
+ return;
+
+ for (i=0; i<array->len; ++i) {
+ SECItem *item = &array->items[i];
+
+ if (item->data) {
+ if (zero_items) {
+ SECITEM_ZfreeItem(item, PR_FALSE);
+ } else {
+ SECITEM_FreeItem(item, PR_FALSE);
+ }
+ }
+ }
+
+ if (freeit)
+ PORT_Free(array);
+}
+
+void SECITEM_FreeArray(SECItemArray *array, PRBool freeit)
+{
+ secitem_FreeArray(array, PR_FALSE, freeit);
+}
+
+void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit)
+{
+ secitem_FreeArray(array, PR_TRUE, freeit);
+}
+
+SECItemArray *
+SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from)
+{
+ SECItemArray *result;
+ unsigned int i;
+
+ if (!from || !from->items || !from->len)
+ return NULL;
+
+ result = SECITEM_AllocArray(arena, NULL, from->len);
+ if (!result)
+ return NULL;
+
+ for (i=0; i<from->len; ++i) {
+ SECStatus rv = SECITEM_CopyItem(arena,
+ &result->items[i], &from->items[i]);
+ if (rv != SECSuccess) {
+ SECITEM_ZfreeArray(result, PR_TRUE);
+ return NULL;
+ }
+ }
+
+ return result;
+}
diff --git a/lib/util/secitem.h b/lib/util/secitem.h
new file mode 100644
index 000000000..dd08da3ff
--- /dev/null
+++ b/lib/util/secitem.h
@@ -0,0 +1,102 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SECITEM_H_
+#define _SECITEM_H_
+
+#include "utilrename.h"
+
+/*
+ * secitem.h - public data structures and prototypes for handling
+ * SECItems
+ *
+ * $Id$
+ */
+
+#include "plarena.h"
+#include "plhash.h"
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Allocate an item. If "arena" is not NULL, then allocate from there,
+** otherwise allocate from the heap. If "item" is not NULL, allocate
+** only the data buffer for the item, not the item itself. If "len" is
+** 0, do not allocate the data buffer for the item; simply set the data
+** field to NULL and the len field to 0. The item structure is allocated
+** zero-filled; the data buffer is not zeroed. The caller is responsible
+** for initializing the type field of the item.
+**
+** The resulting item is returned; NULL if any error occurs.
+**
+** XXX This probably should take a SECItemType, but since that is mostly
+** unused and our improved APIs (aka Stan) are looming, I left it out.
+*/
+extern SECItem *SECITEM_AllocItem(PLArenaPool *arena, SECItem *item,
+ unsigned int len);
+
+/*
+** Reallocate the data for the specified "item". If "arena" is not NULL,
+** then reallocate from there, otherwise reallocate from the heap.
+** In the case where oldlen is 0, the data is allocated (not reallocated).
+** In any case, "item" is expected to be a valid SECItem pointer;
+** SECFailure is returned if it is not. If the allocation succeeds,
+** SECSuccess is returned.
+*/
+extern SECStatus SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item,
+ unsigned int oldlen, unsigned int newlen);
+
+/*
+** Compare two items returning the difference between them.
+*/
+extern SECComparison SECITEM_CompareItem(const SECItem *a, const SECItem *b);
+
+/*
+** Compare two items -- if they are the same, return true; otherwise false.
+*/
+extern PRBool SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b);
+
+/*
+** Copy "from" to "to"
+*/
+extern SECStatus SECITEM_CopyItem(PLArenaPool *arena, SECItem *to,
+ const SECItem *from);
+
+/*
+** Allocate an item and copy "from" into it.
+*/
+extern SECItem *SECITEM_DupItem(const SECItem *from);
+
+/*
+** Allocate an item and copy "from" into it. The item itself and the
+** data it points to are both allocated from the arena. If arena is
+** NULL, this function is equivalent to SECITEM_DupItem.
+*/
+extern SECItem *SECITEM_ArenaDupItem(PLArenaPool *arena, const SECItem *from);
+
+/*
+** Free "zap". If freeit is PR_TRUE then "zap" itself is freed.
+*/
+extern void SECITEM_FreeItem(SECItem *zap, PRBool freeit);
+
+/*
+** Zero and then free "zap". If freeit is PR_TRUE then "zap" itself is freed.
+*/
+extern void SECITEM_ZfreeItem(SECItem *zap, PRBool freeit);
+
+PLHashNumber PR_CALLBACK SECITEM_Hash ( const void *key);
+
+PRIntn PR_CALLBACK SECITEM_HashCompare ( const void *k1, const void *k2);
+
+extern SECItemArray *SECITEM_AllocArray(PLArenaPool *arena,
+ SECItemArray *array,
+ unsigned int len);
+extern SECItemArray *SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from);
+extern void SECITEM_FreeArray(SECItemArray *array, PRBool freeit);
+extern void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit);
+
+SEC_END_PROTOS
+
+#endif /* _SECITEM_H_ */
diff --git a/lib/util/secload.c b/lib/util/secload.c
new file mode 100644
index 000000000..eb8a9ec61
--- /dev/null
+++ b/lib/util/secload.c
@@ -0,0 +1,182 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secport.h"
+#include "nspr.h"
+
+#ifdef XP_UNIX
+#include <unistd.h>
+#define BL_MAXSYMLINKS 20
+
+/*
+ * If 'link' is a symbolic link, this function follows the symbolic links
+ * and returns the pathname of the ultimate source of the symbolic links.
+ * If 'link' is not a symbolic link, this function returns NULL.
+ * The caller should call PR_Free to free the string returned by this
+ * function.
+ */
+static char* loader_GetOriginalPathname(const char* link)
+{
+ char* resolved = NULL;
+ char* input = NULL;
+ PRUint32 iterations = 0;
+ PRInt32 len = 0, retlen = 0;
+ if (!link) {
+ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+ }
+ len = PR_MAX(1024, strlen(link) + 1);
+ resolved = PR_Malloc(len);
+ input = PR_Malloc(len);
+ if (!resolved || !input) {
+ if (resolved) {
+ PR_Free(resolved);
+ }
+ if (input) {
+ PR_Free(input);
+ }
+ return NULL;
+ }
+ strcpy(input, link);
+ while ( (iterations++ < BL_MAXSYMLINKS) &&
+ ( (retlen = readlink(input, resolved, len - 1)) > 0) ) {
+ char* tmp = input;
+ resolved[retlen] = '\0'; /* NULL termination */
+ input = resolved;
+ resolved = tmp;
+ }
+ PR_Free(resolved);
+ if (iterations == 1 && retlen < 0) {
+ PR_Free(input);
+ input = NULL;
+ }
+ return input;
+}
+#endif /* XP_UNIX */
+
+/*
+ * Load the library with the file name 'name' residing in the same
+ * directory as the reference library, whose pathname is 'referencePath'.
+ */
+static PRLibrary *
+loader_LoadLibInReferenceDir(const char *referencePath, const char *name)
+{
+ PRLibrary *dlh = NULL;
+ char *fullName = NULL;
+ char* c;
+ PRLibSpec libSpec;
+
+ /* Remove the trailing filename from referencePath and add the new one */
+ c = strrchr(referencePath, PR_GetDirectorySeparator());
+ if (c) {
+ size_t referencePathSize = 1 + c - referencePath;
+ fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1);
+ if (fullName) {
+ memcpy(fullName, referencePath, referencePathSize);
+ strcpy(fullName + referencePathSize, name);
+#ifdef DEBUG_LOADER
+ PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n",
+ fullName);
+#endif
+ libSpec.type = PR_LibSpec_Pathname;
+ libSpec.value.pathname = fullName;
+ dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL
+#ifdef PR_LD_ALT_SEARCH_PATH
+ /* allow library's dependencies to be found in the same directory
+ * on Windows even if PATH is not set. Requires NSPR 4.8.1 . */
+ | PR_LD_ALT_SEARCH_PATH
+#endif
+ );
+ PORT_Free(fullName);
+ }
+ }
+ return dlh;
+}
+
+/*
+ * Load a shared library called "newShLibName" in the same directory as
+ * a shared library that is already loaded, called existingShLibName.
+ * A pointer to a static function in that shared library,
+ * staticShLibFunc, is required.
+ *
+ * existingShLibName:
+ * The file name of the shared library that shall be used as the
+ * "reference library". The loader will attempt to load the requested
+ * library from the same directory as the reference library.
+ *
+ * staticShLibFunc:
+ * Pointer to a static function in the "reference library".
+ *
+ * newShLibName:
+ * The simple file name of the new shared library to be loaded.
+ *
+ * We use PR_GetLibraryFilePathname to get the pathname of the loaded
+ * shared lib that contains this function, and then do a
+ * PR_LoadLibraryWithFlags with an absolute pathname for the shared
+ * library to be loaded.
+ *
+ * On Windows, the "alternate search path" strategy is employed, if available.
+ * On Unix, if existingShLibName is a symbolic link, and no link exists for the
+ * new library, the original link will be resolved, and the new library loaded
+ * from the resolved location.
+ *
+ * If the new shared library is not found in the same location as the reference
+ * library, it will then be loaded from the normal system library path.
+ *
+ */
+
+PRLibrary *
+PORT_LoadLibraryFromOrigin(const char* existingShLibName,
+ PRFuncPtr staticShLibFunc,
+ const char *newShLibName)
+{
+ PRLibrary *lib = NULL;
+ char* fullPath = NULL;
+ PRLibSpec libSpec;
+
+ /* Get the pathname for existingShLibName, e.g. /usr/lib/libnss3.so
+ * PR_GetLibraryFilePathname works with either the base library name or a
+ * function pointer, depending on the platform.
+ * We require the address of a function in the "reference library",
+ * provided by the caller. To avoid getting the address of the stub/thunk
+ * of an exported function by accident, use the address of a static
+ * function rather than an exported function.
+ */
+ fullPath = PR_GetLibraryFilePathname(existingShLibName,
+ staticShLibFunc);
+
+ if (fullPath) {
+ lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
+#ifdef XP_UNIX
+ if (!lib) {
+ /*
+ * If fullPath is a symbolic link, resolve the symbolic
+ * link and try again.
+ */
+ char* originalfullPath = loader_GetOriginalPathname(fullPath);
+ if (originalfullPath) {
+ PR_Free(fullPath);
+ fullPath = originalfullPath;
+ lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
+ }
+ }
+#endif
+ PR_Free(fullPath);
+ }
+ if (!lib) {
+#ifdef DEBUG_LOADER
+ PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", newShLibName);
+#endif
+ libSpec.type = PR_LibSpec_Pathname;
+ libSpec.value.pathname = newShLibName;
+ lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
+ }
+ if (NULL == lib) {
+#ifdef DEBUG_LOADER
+ PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", newShLibName);
+#endif
+ }
+ return lib;
+}
+
diff --git a/lib/util/secoid.c b/lib/util/secoid.c
new file mode 100644
index 000000000..14ce55636
--- /dev/null
+++ b/lib/util/secoid.c
@@ -0,0 +1,2194 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secoid.h"
+#include "pkcs11t.h"
+#include "secitem.h"
+#include "secerr.h"
+#include "prenv.h"
+#include "plhash.h"
+#include "nssrwlk.h"
+#include "nssutil.h"
+
+/* Library identity and versioning */
+
+#if defined(DEBUG)
+#define _DEBUG_STRING " (debug)"
+#else
+#define _DEBUG_STRING ""
+#endif
+
+/*
+ * Version information for the 'ident' and 'what commands
+ *
+ * NOTE: the first component of the concatenated rcsid string
+ * must not end in a '$' to prevent rcs keyword substitution.
+ */
+const char __nss_util_rcsid[] = "$Header: NSS " NSSUTIL_VERSION _DEBUG_STRING
+ " " __DATE__ " " __TIME__ " $";
+const char __nss_util_sccsid[] = "@(#)NSS " NSSUTIL_VERSION _DEBUG_STRING
+ " " __DATE__ " " __TIME__;
+
+/* MISSI Mosaic Object ID space */
+/* USGov algorithm OID space: { 2 16 840 1 101 } */
+#define USGOV 0x60, 0x86, 0x48, 0x01, 0x65
+#define MISSI USGOV, 0x02, 0x01, 0x01
+#define MISSI_OLD_KEA_DSS MISSI, 0x0c
+#define MISSI_OLD_DSS MISSI, 0x02
+#define MISSI_KEA_DSS MISSI, 0x14
+#define MISSI_DSS MISSI, 0x13
+#define MISSI_KEA MISSI, 0x0a
+#define MISSI_ALT_KEA MISSI, 0x16
+
+#define NISTALGS USGOV, 3, 4
+#define AES NISTALGS, 1
+#define SHAXXX NISTALGS, 2
+#define DSA2 NISTALGS, 3
+
+/**
+ ** The Netscape OID space is allocated by Terry Hayes. If you need
+ ** a piece of the space, contact him at thayes@netscape.com.
+ **/
+
+/* Netscape Communications Corporation Object ID space */
+/* { 2 16 840 1 113730 } */
+#define NETSCAPE_OID 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42
+#define NETSCAPE_CERT_EXT NETSCAPE_OID, 0x01
+#define NETSCAPE_DATA_TYPE NETSCAPE_OID, 0x02
+/* netscape directory oid - owned by Mark Smith (mcs@netscape.com) */
+#define NETSCAPE_DIRECTORY NETSCAPE_OID, 0x03
+#define NETSCAPE_POLICY NETSCAPE_OID, 0x04
+#define NETSCAPE_CERT_SERVER NETSCAPE_OID, 0x05
+#define NETSCAPE_ALGS NETSCAPE_OID, 0x06 /* algorithm OIDs */
+#define NETSCAPE_NAME_COMPONENTS NETSCAPE_OID, 0x07
+
+#define NETSCAPE_CERT_EXT_AIA NETSCAPE_CERT_EXT, 0x10
+#define NETSCAPE_CERT_SERVER_CRMF NETSCAPE_CERT_SERVER, 0x01
+
+/* these are old and should go away soon */
+#define OLD_NETSCAPE 0x60, 0x86, 0x48, 0xd8, 0x6a
+#define NS_CERT_EXT OLD_NETSCAPE, 0x01
+#define NS_FILE_TYPE OLD_NETSCAPE, 0x02
+#define NS_IMAGE_TYPE OLD_NETSCAPE, 0x03
+
+/* RSA OID name space */
+#define RSADSI 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d
+#define PKCS RSADSI, 0x01
+#define DIGEST RSADSI, 0x02
+#define CIPHER RSADSI, 0x03
+#define PKCS1 PKCS, 0x01
+#define PKCS5 PKCS, 0x05
+#define PKCS7 PKCS, 0x07
+#define PKCS9 PKCS, 0x09
+#define PKCS12 PKCS, 0x0c
+
+/* Other OID name spaces */
+#define ALGORITHM 0x2b, 0x0e, 0x03, 0x02
+#define X500 0x55
+#define X520_ATTRIBUTE_TYPE X500, 0x04
+#define X500_ALG X500, 0x08
+#define X500_ALG_ENCRYPTION X500_ALG, 0x01
+
+/** X.509 v3 Extension OID
+ ** {joint-iso-ccitt (2) ds(5) 29}
+ **/
+#define ID_CE_OID X500, 0x1d
+
+#define RFC1274_ATTR_TYPE 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x1
+/* #define RFC2247_ATTR_TYPE 0x09, 0x92, 0x26, 0xf5, 0x98, 0x1e, 0x64, 0x1 this is WRONG! */
+
+/* PKCS #12 name spaces */
+#define PKCS12_MODE_IDS PKCS12, 0x01
+#define PKCS12_ESPVK_IDS PKCS12, 0x02
+#define PKCS12_BAG_IDS PKCS12, 0x03
+#define PKCS12_CERT_BAG_IDS PKCS12, 0x04
+#define PKCS12_OIDS PKCS12, 0x05
+#define PKCS12_PBE_IDS PKCS12_OIDS, 0x01
+#define PKCS12_ENVELOPING_IDS PKCS12_OIDS, 0x02
+#define PKCS12_SIGNATURE_IDS PKCS12_OIDS, 0x03
+#define PKCS12_V2_PBE_IDS PKCS12, 0x01
+#define PKCS9_CERT_TYPES PKCS9, 0x16
+#define PKCS9_CRL_TYPES PKCS9, 0x17
+#define PKCS9_SMIME_IDS PKCS9, 0x10
+#define PKCS9_SMIME_ATTRS PKCS9_SMIME_IDS, 2
+#define PKCS9_SMIME_ALGS PKCS9_SMIME_IDS, 3
+#define PKCS12_VERSION1 PKCS12, 0x0a
+#define PKCS12_V1_BAG_IDS PKCS12_VERSION1, 1
+
+/* for DSA algorithm */
+/* { iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) } */
+#define ANSI_X9_ALGORITHM 0x2a, 0x86, 0x48, 0xce, 0x38, 0x4
+
+/* for DH algorithm */
+/* { iso(1) member-body(2) us(840) x9-57(10046) number-type(2) } */
+/* need real OID person to look at this, copied the above line
+ * and added 6 to second to last value (and changed '4' to '2' */
+#define ANSI_X942_ALGORITHM 0x2a, 0x86, 0x48, 0xce, 0x3e, 0x2
+
+#define VERISIGN 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45
+
+#define PKIX 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07
+#define PKIX_CERT_EXTENSIONS PKIX, 1
+#define PKIX_POLICY_QUALIFIERS PKIX, 2
+#define PKIX_KEY_USAGE PKIX, 3
+#define PKIX_ACCESS_DESCRIPTION PKIX, 0x30
+#define PKIX_OCSP PKIX_ACCESS_DESCRIPTION, 1
+#define PKIX_CA_ISSUERS PKIX_ACCESS_DESCRIPTION, 2
+
+#define PKIX_ID_PKIP PKIX, 5
+#define PKIX_ID_REGCTRL PKIX_ID_PKIP, 1
+#define PKIX_ID_REGINFO PKIX_ID_PKIP, 2
+
+/* Microsoft Object ID space */
+/* { 1.3.6.1.4.1.311 } */
+#define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37
+#define EV_NAME_ATTRIBUTE MICROSOFT_OID, 60, 2, 1
+
+/* Microsoft Crypto 2.0 ID space */
+/* { 1.3.6.1.4.1.311.10 } */
+#define MS_CRYPTO_20 MICROSOFT_OID, 10
+/* Microsoft Crypto 2.0 Extended Key Usage ID space */
+/* { 1.3.6.1.4.1.311.10.3 } */
+#define MS_CRYPTO_EKU MS_CRYPTO_20, 3
+
+#define CERTICOM_OID 0x2b, 0x81, 0x04
+#define SECG_OID CERTICOM_OID, 0x00
+
+#define ANSI_X962_OID 0x2a, 0x86, 0x48, 0xce, 0x3d
+#define ANSI_X962_CURVE_OID ANSI_X962_OID, 0x03
+#define ANSI_X962_GF2m_OID ANSI_X962_CURVE_OID, 0x00
+#define ANSI_X962_GFp_OID ANSI_X962_CURVE_OID, 0x01
+#define ANSI_X962_SIGNATURE_OID ANSI_X962_OID, 0x04
+#define ANSI_X962_SPECIFY_OID ANSI_X962_SIGNATURE_OID, 0x03
+
+/* for Camellia: iso(1) member-body(2) jisc(392)
+ * mitsubishi(200011) isl(61) security(1) algorithm(1)
+ */
+#define MITSUBISHI_ALG 0x2a,0x83,0x08,0x8c,0x9a,0x4b,0x3d,0x01,0x01
+#define CAMELLIA_ENCRYPT_OID MITSUBISHI_ALG,1
+#define CAMELLIA_WRAP_OID MITSUBISHI_ALG,3
+
+/* for SEED : iso(1) member-body(2) korea(410)
+ * kisa(200004) algorithm(1)
+ */
+#define SEED_OID 0x2a,0x83,0x1a,0x8c,0x9a,0x44,0x01
+
+#define CONST_OID static const unsigned char
+
+CONST_OID md2[] = { DIGEST, 0x02 };
+CONST_OID md4[] = { DIGEST, 0x04 };
+CONST_OID md5[] = { DIGEST, 0x05 };
+CONST_OID hmac_sha1[] = { DIGEST, 7 };
+CONST_OID hmac_sha224[] = { DIGEST, 8 };
+CONST_OID hmac_sha256[] = { DIGEST, 9 };
+CONST_OID hmac_sha384[] = { DIGEST, 10 };
+CONST_OID hmac_sha512[] = { DIGEST, 11 };
+
+CONST_OID rc2cbc[] = { CIPHER, 0x02 };
+CONST_OID rc4[] = { CIPHER, 0x04 };
+CONST_OID desede3cbc[] = { CIPHER, 0x07 };
+CONST_OID rc5cbcpad[] = { CIPHER, 0x09 };
+
+CONST_OID desecb[] = { ALGORITHM, 0x06 };
+CONST_OID descbc[] = { ALGORITHM, 0x07 };
+CONST_OID desofb[] = { ALGORITHM, 0x08 };
+CONST_OID descfb[] = { ALGORITHM, 0x09 };
+CONST_OID desmac[] = { ALGORITHM, 0x0a };
+CONST_OID sdn702DSASignature[] = { ALGORITHM, 0x0c };
+CONST_OID isoSHAWithRSASignature[] = { ALGORITHM, 0x0f };
+CONST_OID desede[] = { ALGORITHM, 0x11 };
+CONST_OID sha1[] = { ALGORITHM, 0x1a };
+CONST_OID bogusDSASignaturewithSHA1Digest[] = { ALGORITHM, 0x1b };
+CONST_OID isoSHA1WithRSASignature[] = { ALGORITHM, 0x1d };
+
+CONST_OID pkcs1RSAEncryption[] = { PKCS1, 0x01 };
+CONST_OID pkcs1MD2WithRSAEncryption[] = { PKCS1, 0x02 };
+CONST_OID pkcs1MD4WithRSAEncryption[] = { PKCS1, 0x03 };
+CONST_OID pkcs1MD5WithRSAEncryption[] = { PKCS1, 0x04 };
+CONST_OID pkcs1SHA1WithRSAEncryption[] = { PKCS1, 0x05 };
+CONST_OID pkcs1RSAOAEPEncryption[] = { PKCS1, 0x07 };
+CONST_OID pkcs1MGF1[] = { PKCS1, 0x08 };
+CONST_OID pkcs1PSpecified[] = { PKCS1, 0x09 };
+CONST_OID pkcs1RSAPSSSignature[] = { PKCS1, 10 };
+CONST_OID pkcs1SHA256WithRSAEncryption[] = { PKCS1, 11 };
+CONST_OID pkcs1SHA384WithRSAEncryption[] = { PKCS1, 12 };
+CONST_OID pkcs1SHA512WithRSAEncryption[] = { PKCS1, 13 };
+CONST_OID pkcs1SHA224WithRSAEncryption[] = { PKCS1, 14 };
+
+CONST_OID pkcs5PbeWithMD2AndDEScbc[] = { PKCS5, 0x01 };
+CONST_OID pkcs5PbeWithMD5AndDEScbc[] = { PKCS5, 0x03 };
+CONST_OID pkcs5PbeWithSha1AndDEScbc[] = { PKCS5, 0x0a };
+CONST_OID pkcs5Pbkdf2[] = { PKCS5, 12 };
+CONST_OID pkcs5Pbes2[] = { PKCS5, 13 };
+CONST_OID pkcs5Pbmac1[] = { PKCS5, 14 };
+
+CONST_OID pkcs7[] = { PKCS7 };
+CONST_OID pkcs7Data[] = { PKCS7, 0x01 };
+CONST_OID pkcs7SignedData[] = { PKCS7, 0x02 };
+CONST_OID pkcs7EnvelopedData[] = { PKCS7, 0x03 };
+CONST_OID pkcs7SignedEnvelopedData[] = { PKCS7, 0x04 };
+CONST_OID pkcs7DigestedData[] = { PKCS7, 0x05 };
+CONST_OID pkcs7EncryptedData[] = { PKCS7, 0x06 };
+
+CONST_OID pkcs9EmailAddress[] = { PKCS9, 0x01 };
+CONST_OID pkcs9UnstructuredName[] = { PKCS9, 0x02 };
+CONST_OID pkcs9ContentType[] = { PKCS9, 0x03 };
+CONST_OID pkcs9MessageDigest[] = { PKCS9, 0x04 };
+CONST_OID pkcs9SigningTime[] = { PKCS9, 0x05 };
+CONST_OID pkcs9CounterSignature[] = { PKCS9, 0x06 };
+CONST_OID pkcs9ChallengePassword[] = { PKCS9, 0x07 };
+CONST_OID pkcs9UnstructuredAddress[] = { PKCS9, 0x08 };
+CONST_OID pkcs9ExtendedCertificateAttributes[] = { PKCS9, 0x09 };
+CONST_OID pkcs9ExtensionRequest[] = { PKCS9, 14 };
+CONST_OID pkcs9SMIMECapabilities[] = { PKCS9, 15 };
+CONST_OID pkcs9FriendlyName[] = { PKCS9, 20 };
+CONST_OID pkcs9LocalKeyID[] = { PKCS9, 21 };
+
+CONST_OID pkcs9X509Certificate[] = { PKCS9_CERT_TYPES, 1 };
+CONST_OID pkcs9SDSICertificate[] = { PKCS9_CERT_TYPES, 2 };
+CONST_OID pkcs9X509CRL[] = { PKCS9_CRL_TYPES, 1 };
+
+/* RFC2630 (CMS) OIDs */
+CONST_OID cmsESDH[] = { PKCS9_SMIME_ALGS, 5 };
+CONST_OID cms3DESwrap[] = { PKCS9_SMIME_ALGS, 6 };
+CONST_OID cmsRC2wrap[] = { PKCS9_SMIME_ALGS, 7 };
+
+/* RFC2633 SMIME message attributes */
+CONST_OID smimeEncryptionKeyPreference[] = { PKCS9_SMIME_ATTRS, 11 };
+CONST_OID ms_smimeEncryptionKeyPreference[] = { MICROSOFT_OID, 0x10, 0x4 };
+
+CONST_OID x520CommonName[] = { X520_ATTRIBUTE_TYPE, 3 };
+CONST_OID x520SurName[] = { X520_ATTRIBUTE_TYPE, 4 };
+CONST_OID x520SerialNumber[] = { X520_ATTRIBUTE_TYPE, 5 };
+CONST_OID x520CountryName[] = { X520_ATTRIBUTE_TYPE, 6 };
+CONST_OID x520LocalityName[] = { X520_ATTRIBUTE_TYPE, 7 };
+CONST_OID x520StateOrProvinceName[] = { X520_ATTRIBUTE_TYPE, 8 };
+CONST_OID x520StreetAddress[] = { X520_ATTRIBUTE_TYPE, 9 };
+CONST_OID x520OrgName[] = { X520_ATTRIBUTE_TYPE, 10 };
+CONST_OID x520OrgUnitName[] = { X520_ATTRIBUTE_TYPE, 11 };
+CONST_OID x520Title[] = { X520_ATTRIBUTE_TYPE, 12 };
+CONST_OID x520BusinessCategory[] = { X520_ATTRIBUTE_TYPE, 15 };
+CONST_OID x520PostalAddress[] = { X520_ATTRIBUTE_TYPE, 16 };
+CONST_OID x520PostalCode[] = { X520_ATTRIBUTE_TYPE, 17 };
+CONST_OID x520PostOfficeBox[] = { X520_ATTRIBUTE_TYPE, 18 };
+CONST_OID x520GivenName[] = { X520_ATTRIBUTE_TYPE, 42 };
+CONST_OID x520Initials[] = { X520_ATTRIBUTE_TYPE, 43 };
+CONST_OID x520GenerationQualifier[] = { X520_ATTRIBUTE_TYPE, 44 };
+CONST_OID x520DnQualifier[] = { X520_ATTRIBUTE_TYPE, 46 };
+CONST_OID x520HouseIdentifier[] = { X520_ATTRIBUTE_TYPE, 51 };
+CONST_OID x520Pseudonym[] = { X520_ATTRIBUTE_TYPE, 65 };
+
+CONST_OID nsTypeGIF[] = { NETSCAPE_DATA_TYPE, 0x01 };
+CONST_OID nsTypeJPEG[] = { NETSCAPE_DATA_TYPE, 0x02 };
+CONST_OID nsTypeURL[] = { NETSCAPE_DATA_TYPE, 0x03 };
+CONST_OID nsTypeHTML[] = { NETSCAPE_DATA_TYPE, 0x04 };
+CONST_OID nsTypeCertSeq[] = { NETSCAPE_DATA_TYPE, 0x05 };
+
+CONST_OID missiCertKEADSSOld[] = { MISSI_OLD_KEA_DSS };
+CONST_OID missiCertDSSOld[] = { MISSI_OLD_DSS };
+CONST_OID missiCertKEADSS[] = { MISSI_KEA_DSS };
+CONST_OID missiCertDSS[] = { MISSI_DSS };
+CONST_OID missiCertKEA[] = { MISSI_KEA };
+CONST_OID missiCertAltKEA[] = { MISSI_ALT_KEA };
+CONST_OID x500RSAEncryption[] = { X500_ALG_ENCRYPTION, 0x01 };
+
+/* added for alg 1485 */
+CONST_OID rfc1274Uid[] = { RFC1274_ATTR_TYPE, 1 };
+CONST_OID rfc1274Mail[] = { RFC1274_ATTR_TYPE, 3 };
+CONST_OID rfc2247DomainComponent[] = { RFC1274_ATTR_TYPE, 25 };
+
+/* Netscape private certificate extensions */
+CONST_OID nsCertExtNetscapeOK[] = { NS_CERT_EXT, 1 };
+CONST_OID nsCertExtIssuerLogo[] = { NS_CERT_EXT, 2 };
+CONST_OID nsCertExtSubjectLogo[] = { NS_CERT_EXT, 3 };
+CONST_OID nsExtCertType[] = { NETSCAPE_CERT_EXT, 0x01 };
+CONST_OID nsExtBaseURL[] = { NETSCAPE_CERT_EXT, 0x02 };
+CONST_OID nsExtRevocationURL[] = { NETSCAPE_CERT_EXT, 0x03 };
+CONST_OID nsExtCARevocationURL[] = { NETSCAPE_CERT_EXT, 0x04 };
+CONST_OID nsExtCACRLURL[] = { NETSCAPE_CERT_EXT, 0x05 };
+CONST_OID nsExtCACertURL[] = { NETSCAPE_CERT_EXT, 0x06 };
+CONST_OID nsExtCertRenewalURL[] = { NETSCAPE_CERT_EXT, 0x07 };
+CONST_OID nsExtCAPolicyURL[] = { NETSCAPE_CERT_EXT, 0x08 };
+CONST_OID nsExtHomepageURL[] = { NETSCAPE_CERT_EXT, 0x09 };
+CONST_OID nsExtEntityLogo[] = { NETSCAPE_CERT_EXT, 0x0a };
+CONST_OID nsExtUserPicture[] = { NETSCAPE_CERT_EXT, 0x0b };
+CONST_OID nsExtSSLServerName[] = { NETSCAPE_CERT_EXT, 0x0c };
+CONST_OID nsExtComment[] = { NETSCAPE_CERT_EXT, 0x0d };
+
+/* the following 2 extensions are defined for and used by Cartman(NSM) */
+CONST_OID nsExtLostPasswordURL[] = { NETSCAPE_CERT_EXT, 0x0e };
+CONST_OID nsExtCertRenewalTime[] = { NETSCAPE_CERT_EXT, 0x0f };
+
+CONST_OID nsExtAIACertRenewal[] = { NETSCAPE_CERT_EXT_AIA, 0x01 };
+CONST_OID nsExtCertScopeOfUse[] = { NETSCAPE_CERT_EXT, 0x11 };
+/* Reserved Netscape (2 16 840 1 113730 1 18) = { NETSCAPE_CERT_EXT, 0x12 }; */
+
+/* Netscape policy values */
+CONST_OID nsKeyUsageGovtApproved[] = { NETSCAPE_POLICY, 0x01 };
+
+/* Netscape other name types */
+CONST_OID netscapeNickname[] = { NETSCAPE_NAME_COMPONENTS, 0x01 };
+CONST_OID netscapeAOLScreenname[] = { NETSCAPE_NAME_COMPONENTS, 0x02 };
+
+/* OIDs needed for cert server */
+CONST_OID netscapeRecoveryRequest[] = { NETSCAPE_CERT_SERVER_CRMF, 0x01 };
+
+
+/* Standard x.509 v3 Certificate & CRL Extensions */
+CONST_OID x509SubjectDirectoryAttr[] = { ID_CE_OID, 9 };
+CONST_OID x509SubjectKeyID[] = { ID_CE_OID, 14 };
+CONST_OID x509KeyUsage[] = { ID_CE_OID, 15 };
+CONST_OID x509PrivateKeyUsagePeriod[] = { ID_CE_OID, 16 };
+CONST_OID x509SubjectAltName[] = { ID_CE_OID, 17 };
+CONST_OID x509IssuerAltName[] = { ID_CE_OID, 18 };
+CONST_OID x509BasicConstraints[] = { ID_CE_OID, 19 };
+CONST_OID x509CRLNumber[] = { ID_CE_OID, 20 };
+CONST_OID x509ReasonCode[] = { ID_CE_OID, 21 };
+CONST_OID x509HoldInstructionCode[] = { ID_CE_OID, 23 };
+CONST_OID x509InvalidDate[] = { ID_CE_OID, 24 };
+CONST_OID x509DeltaCRLIndicator[] = { ID_CE_OID, 27 };
+CONST_OID x509IssuingDistributionPoint[] = { ID_CE_OID, 28 };
+CONST_OID x509CertIssuer[] = { ID_CE_OID, 29 };
+CONST_OID x509NameConstraints[] = { ID_CE_OID, 30 };
+CONST_OID x509CRLDistPoints[] = { ID_CE_OID, 31 };
+CONST_OID x509CertificatePolicies[] = { ID_CE_OID, 32 };
+CONST_OID x509PolicyMappings[] = { ID_CE_OID, 33 };
+CONST_OID x509AuthKeyID[] = { ID_CE_OID, 35 };
+CONST_OID x509PolicyConstraints[] = { ID_CE_OID, 36 };
+CONST_OID x509ExtKeyUsage[] = { ID_CE_OID, 37 };
+CONST_OID x509FreshestCRL[] = { ID_CE_OID, 46 };
+CONST_OID x509InhibitAnyPolicy[] = { ID_CE_OID, 54 };
+
+CONST_OID x509CertificatePoliciesAnyPolicy[] = { ID_CE_OID, 32, 0 };
+
+CONST_OID x509AuthInfoAccess[] = { PKIX_CERT_EXTENSIONS, 1 };
+CONST_OID x509SubjectInfoAccess[] = { PKIX_CERT_EXTENSIONS, 11 };
+
+CONST_OID x509SIATimeStamping[] = {PKIX_ACCESS_DESCRIPTION, 0x03};
+CONST_OID x509SIACaRepository[] = {PKIX_ACCESS_DESCRIPTION, 0x05};
+
+/* pkcs 12 additions */
+CONST_OID pkcs12[] = { PKCS12 };
+CONST_OID pkcs12ModeIDs[] = { PKCS12_MODE_IDS };
+CONST_OID pkcs12ESPVKIDs[] = { PKCS12_ESPVK_IDS };
+CONST_OID pkcs12BagIDs[] = { PKCS12_BAG_IDS };
+CONST_OID pkcs12CertBagIDs[] = { PKCS12_CERT_BAG_IDS };
+CONST_OID pkcs12OIDs[] = { PKCS12_OIDS };
+CONST_OID pkcs12PBEIDs[] = { PKCS12_PBE_IDS };
+CONST_OID pkcs12EnvelopingIDs[] = { PKCS12_ENVELOPING_IDS };
+CONST_OID pkcs12SignatureIDs[] = { PKCS12_SIGNATURE_IDS };
+CONST_OID pkcs12PKCS8KeyShrouding[] = { PKCS12_ESPVK_IDS, 0x01 };
+CONST_OID pkcs12KeyBagID[] = { PKCS12_BAG_IDS, 0x01 };
+CONST_OID pkcs12CertAndCRLBagID[] = { PKCS12_BAG_IDS, 0x02 };
+CONST_OID pkcs12SecretBagID[] = { PKCS12_BAG_IDS, 0x03 };
+CONST_OID pkcs12X509CertCRLBag[] = { PKCS12_CERT_BAG_IDS, 0x01 };
+CONST_OID pkcs12SDSICertBag[] = { PKCS12_CERT_BAG_IDS, 0x02 };
+CONST_OID pkcs12PBEWithSha1And128BitRC4[] = { PKCS12_PBE_IDS, 0x01 };
+CONST_OID pkcs12PBEWithSha1And40BitRC4[] = { PKCS12_PBE_IDS, 0x02 };
+CONST_OID pkcs12PBEWithSha1AndTripleDESCBC[] = { PKCS12_PBE_IDS, 0x03 };
+CONST_OID pkcs12PBEWithSha1And128BitRC2CBC[] = { PKCS12_PBE_IDS, 0x04 };
+CONST_OID pkcs12PBEWithSha1And40BitRC2CBC[] = { PKCS12_PBE_IDS, 0x05 };
+CONST_OID pkcs12RSAEncryptionWith128BitRC4[] = { PKCS12_ENVELOPING_IDS, 0x01 };
+CONST_OID pkcs12RSAEncryptionWith40BitRC4[] = { PKCS12_ENVELOPING_IDS, 0x02 };
+CONST_OID pkcs12RSAEncryptionWithTripleDES[] = { PKCS12_ENVELOPING_IDS, 0x03 };
+CONST_OID pkcs12RSASignatureWithSHA1Digest[] = { PKCS12_SIGNATURE_IDS, 0x01 };
+
+/* pkcs 12 version 1.0 ids */
+CONST_OID pkcs12V2PBEWithSha1And128BitRC4[] = { PKCS12_V2_PBE_IDS, 0x01 };
+CONST_OID pkcs12V2PBEWithSha1And40BitRC4[] = { PKCS12_V2_PBE_IDS, 0x02 };
+CONST_OID pkcs12V2PBEWithSha1And3KeyTripleDEScbc[]= { PKCS12_V2_PBE_IDS, 0x03 };
+CONST_OID pkcs12V2PBEWithSha1And2KeyTripleDEScbc[]= { PKCS12_V2_PBE_IDS, 0x04 };
+CONST_OID pkcs12V2PBEWithSha1And128BitRC2cbc[] = { PKCS12_V2_PBE_IDS, 0x05 };
+CONST_OID pkcs12V2PBEWithSha1And40BitRC2cbc[] = { PKCS12_V2_PBE_IDS, 0x06 };
+
+CONST_OID pkcs12SafeContentsID[] = { PKCS12_BAG_IDS, 0x04 };
+CONST_OID pkcs12PKCS8ShroudedKeyBagID[] = { PKCS12_BAG_IDS, 0x05 };
+
+CONST_OID pkcs12V1KeyBag[] = { PKCS12_V1_BAG_IDS, 0x01 };
+CONST_OID pkcs12V1PKCS8ShroudedKeyBag[] = { PKCS12_V1_BAG_IDS, 0x02 };
+CONST_OID pkcs12V1CertBag[] = { PKCS12_V1_BAG_IDS, 0x03 };
+CONST_OID pkcs12V1CRLBag[] = { PKCS12_V1_BAG_IDS, 0x04 };
+CONST_OID pkcs12V1SecretBag[] = { PKCS12_V1_BAG_IDS, 0x05 };
+CONST_OID pkcs12V1SafeContentsBag[] = { PKCS12_V1_BAG_IDS, 0x06 };
+
+/* The following encoding is INCORRECT, but correcting it would create a
+ * duplicate OID in the table. So, we will leave it alone.
+ */
+CONST_OID pkcs12KeyUsageAttr[] = { 2, 5, 29, 15 };
+
+CONST_OID ansix9DSASignature[] = { ANSI_X9_ALGORITHM, 0x01 };
+CONST_OID ansix9DSASignaturewithSHA1Digest[] = { ANSI_X9_ALGORITHM, 0x03 };
+CONST_OID nistDSASignaturewithSHA224Digest[] = { DSA2, 0x01 };
+CONST_OID nistDSASignaturewithSHA256Digest[] = { DSA2, 0x02 };
+
+/* verisign OIDs */
+CONST_OID verisignUserNotices[] = { VERISIGN, 1, 7, 1, 1 };
+
+/* pkix OIDs */
+CONST_OID pkixCPSPointerQualifier[] = { PKIX_POLICY_QUALIFIERS, 1 };
+CONST_OID pkixUserNoticeQualifier[] = { PKIX_POLICY_QUALIFIERS, 2 };
+
+CONST_OID pkixOCSP[] = { PKIX_OCSP };
+CONST_OID pkixOCSPBasicResponse[] = { PKIX_OCSP, 1 };
+CONST_OID pkixOCSPNonce[] = { PKIX_OCSP, 2 };
+CONST_OID pkixOCSPCRL[] = { PKIX_OCSP, 3 };
+CONST_OID pkixOCSPResponse[] = { PKIX_OCSP, 4 };
+CONST_OID pkixOCSPNoCheck[] = { PKIX_OCSP, 5 };
+CONST_OID pkixOCSPArchiveCutoff[] = { PKIX_OCSP, 6 };
+CONST_OID pkixOCSPServiceLocator[] = { PKIX_OCSP, 7 };
+
+CONST_OID pkixCAIssuers[] = { PKIX_CA_ISSUERS };
+
+CONST_OID pkixRegCtrlRegToken[] = { PKIX_ID_REGCTRL, 1};
+CONST_OID pkixRegCtrlAuthenticator[] = { PKIX_ID_REGCTRL, 2};
+CONST_OID pkixRegCtrlPKIPubInfo[] = { PKIX_ID_REGCTRL, 3};
+CONST_OID pkixRegCtrlPKIArchOptions[] = { PKIX_ID_REGCTRL, 4};
+CONST_OID pkixRegCtrlOldCertID[] = { PKIX_ID_REGCTRL, 5};
+CONST_OID pkixRegCtrlProtEncKey[] = { PKIX_ID_REGCTRL, 6};
+CONST_OID pkixRegInfoUTF8Pairs[] = { PKIX_ID_REGINFO, 1};
+CONST_OID pkixRegInfoCertReq[] = { PKIX_ID_REGINFO, 2};
+
+CONST_OID pkixExtendedKeyUsageServerAuth[] = { PKIX_KEY_USAGE, 1 };
+CONST_OID pkixExtendedKeyUsageClientAuth[] = { PKIX_KEY_USAGE, 2 };
+CONST_OID pkixExtendedKeyUsageCodeSign[] = { PKIX_KEY_USAGE, 3 };
+CONST_OID pkixExtendedKeyUsageEMailProtect[] = { PKIX_KEY_USAGE, 4 };
+CONST_OID pkixExtendedKeyUsageTimeStamp[] = { PKIX_KEY_USAGE, 8 };
+CONST_OID pkixOCSPResponderExtendedKeyUsage[] = { PKIX_KEY_USAGE, 9 };
+CONST_OID msExtendedKeyUsageTrustListSigning[] = { MS_CRYPTO_EKU, 1 };
+
+/* OIDs for Netscape defined algorithms */
+CONST_OID netscapeSMimeKEA[] = { NETSCAPE_ALGS, 0x01 };
+
+/* Fortezza algorithm OIDs */
+CONST_OID skipjackCBC[] = { MISSI, 0x04 };
+CONST_OID dhPublicKey[] = { ANSI_X942_ALGORITHM, 0x1 };
+
+CONST_OID aes128_ECB[] = { AES, 1 };
+CONST_OID aes128_CBC[] = { AES, 2 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes128_OFB[] = { AES, 3 };
+CONST_OID aes128_CFB[] = { AES, 4 };
+#endif
+CONST_OID aes128_KEY_WRAP[] = { AES, 5 };
+
+CONST_OID aes192_ECB[] = { AES, 21 };
+CONST_OID aes192_CBC[] = { AES, 22 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes192_OFB[] = { AES, 23 };
+CONST_OID aes192_CFB[] = { AES, 24 };
+#endif
+CONST_OID aes192_KEY_WRAP[] = { AES, 25 };
+
+CONST_OID aes256_ECB[] = { AES, 41 };
+CONST_OID aes256_CBC[] = { AES, 42 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes256_OFB[] = { AES, 43 };
+CONST_OID aes256_CFB[] = { AES, 44 };
+#endif
+CONST_OID aes256_KEY_WRAP[] = { AES, 45 };
+
+CONST_OID camellia128_CBC[] = { CAMELLIA_ENCRYPT_OID, 2};
+CONST_OID camellia192_CBC[] = { CAMELLIA_ENCRYPT_OID, 3};
+CONST_OID camellia256_CBC[] = { CAMELLIA_ENCRYPT_OID, 4};
+CONST_OID camellia128_KEY_WRAP[] = { CAMELLIA_WRAP_OID, 2};
+CONST_OID camellia192_KEY_WRAP[] = { CAMELLIA_WRAP_OID, 3};
+CONST_OID camellia256_KEY_WRAP[] = { CAMELLIA_WRAP_OID, 4};
+
+CONST_OID sha256[] = { SHAXXX, 1 };
+CONST_OID sha384[] = { SHAXXX, 2 };
+CONST_OID sha512[] = { SHAXXX, 3 };
+CONST_OID sha224[] = { SHAXXX, 4 };
+
+CONST_OID ansix962ECPublicKey[] = { ANSI_X962_OID, 0x02, 0x01 };
+CONST_OID ansix962SignaturewithSHA1Digest[] = { ANSI_X962_SIGNATURE_OID, 0x01 };
+CONST_OID ansix962SignatureRecommended[] = { ANSI_X962_SIGNATURE_OID, 0x02 };
+CONST_OID ansix962SignatureSpecified[] = { ANSI_X962_SPECIFY_OID };
+CONST_OID ansix962SignaturewithSHA224Digest[] = { ANSI_X962_SPECIFY_OID, 0x01 };
+CONST_OID ansix962SignaturewithSHA256Digest[] = { ANSI_X962_SPECIFY_OID, 0x02 };
+CONST_OID ansix962SignaturewithSHA384Digest[] = { ANSI_X962_SPECIFY_OID, 0x03 };
+CONST_OID ansix962SignaturewithSHA512Digest[] = { ANSI_X962_SPECIFY_OID, 0x04 };
+
+/* ANSI X9.62 prime curve OIDs */
+/* NOTE: prime192v1 is the same as secp192r1, prime256v1 is the
+ * same as secp256r1
+ */
+CONST_OID ansiX962prime192v1[] = { ANSI_X962_GFp_OID, 0x01 };
+CONST_OID ansiX962prime192v2[] = { ANSI_X962_GFp_OID, 0x02 };
+CONST_OID ansiX962prime192v3[] = { ANSI_X962_GFp_OID, 0x03 };
+CONST_OID ansiX962prime239v1[] = { ANSI_X962_GFp_OID, 0x04 };
+CONST_OID ansiX962prime239v2[] = { ANSI_X962_GFp_OID, 0x05 };
+CONST_OID ansiX962prime239v3[] = { ANSI_X962_GFp_OID, 0x06 };
+CONST_OID ansiX962prime256v1[] = { ANSI_X962_GFp_OID, 0x07 };
+
+/* SECG prime curve OIDs */
+CONST_OID secgECsecp112r1[] = { SECG_OID, 0x06 };
+CONST_OID secgECsecp112r2[] = { SECG_OID, 0x07 };
+CONST_OID secgECsecp128r1[] = { SECG_OID, 0x1c };
+CONST_OID secgECsecp128r2[] = { SECG_OID, 0x1d };
+CONST_OID secgECsecp160k1[] = { SECG_OID, 0x09 };
+CONST_OID secgECsecp160r1[] = { SECG_OID, 0x08 };
+CONST_OID secgECsecp160r2[] = { SECG_OID, 0x1e };
+CONST_OID secgECsecp192k1[] = { SECG_OID, 0x1f };
+CONST_OID secgECsecp224k1[] = { SECG_OID, 0x20 };
+CONST_OID secgECsecp224r1[] = { SECG_OID, 0x21 };
+CONST_OID secgECsecp256k1[] = { SECG_OID, 0x0a };
+CONST_OID secgECsecp384r1[] = { SECG_OID, 0x22 };
+CONST_OID secgECsecp521r1[] = { SECG_OID, 0x23 };
+
+/* ANSI X9.62 characteristic two curve OIDs */
+CONST_OID ansiX962c2pnb163v1[] = { ANSI_X962_GF2m_OID, 0x01 };
+CONST_OID ansiX962c2pnb163v2[] = { ANSI_X962_GF2m_OID, 0x02 };
+CONST_OID ansiX962c2pnb163v3[] = { ANSI_X962_GF2m_OID, 0x03 };
+CONST_OID ansiX962c2pnb176v1[] = { ANSI_X962_GF2m_OID, 0x04 };
+CONST_OID ansiX962c2tnb191v1[] = { ANSI_X962_GF2m_OID, 0x05 };
+CONST_OID ansiX962c2tnb191v2[] = { ANSI_X962_GF2m_OID, 0x06 };
+CONST_OID ansiX962c2tnb191v3[] = { ANSI_X962_GF2m_OID, 0x07 };
+CONST_OID ansiX962c2onb191v4[] = { ANSI_X962_GF2m_OID, 0x08 };
+CONST_OID ansiX962c2onb191v5[] = { ANSI_X962_GF2m_OID, 0x09 };
+CONST_OID ansiX962c2pnb208w1[] = { ANSI_X962_GF2m_OID, 0x0a };
+CONST_OID ansiX962c2tnb239v1[] = { ANSI_X962_GF2m_OID, 0x0b };
+CONST_OID ansiX962c2tnb239v2[] = { ANSI_X962_GF2m_OID, 0x0c };
+CONST_OID ansiX962c2tnb239v3[] = { ANSI_X962_GF2m_OID, 0x0d };
+CONST_OID ansiX962c2onb239v4[] = { ANSI_X962_GF2m_OID, 0x0e };
+CONST_OID ansiX962c2onb239v5[] = { ANSI_X962_GF2m_OID, 0x0f };
+CONST_OID ansiX962c2pnb272w1[] = { ANSI_X962_GF2m_OID, 0x10 };
+CONST_OID ansiX962c2pnb304w1[] = { ANSI_X962_GF2m_OID, 0x11 };
+CONST_OID ansiX962c2tnb359v1[] = { ANSI_X962_GF2m_OID, 0x12 };
+CONST_OID ansiX962c2pnb368w1[] = { ANSI_X962_GF2m_OID, 0x13 };
+CONST_OID ansiX962c2tnb431r1[] = { ANSI_X962_GF2m_OID, 0x14 };
+
+/* SECG characterisitic two curve OIDs */
+CONST_OID secgECsect113r1[] = {SECG_OID, 0x04 };
+CONST_OID secgECsect113r2[] = {SECG_OID, 0x05 };
+CONST_OID secgECsect131r1[] = {SECG_OID, 0x16 };
+CONST_OID secgECsect131r2[] = {SECG_OID, 0x17 };
+CONST_OID secgECsect163k1[] = {SECG_OID, 0x01 };
+CONST_OID secgECsect163r1[] = {SECG_OID, 0x02 };
+CONST_OID secgECsect163r2[] = {SECG_OID, 0x0f };
+CONST_OID secgECsect193r1[] = {SECG_OID, 0x18 };
+CONST_OID secgECsect193r2[] = {SECG_OID, 0x19 };
+CONST_OID secgECsect233k1[] = {SECG_OID, 0x1a };
+CONST_OID secgECsect233r1[] = {SECG_OID, 0x1b };
+CONST_OID secgECsect239k1[] = {SECG_OID, 0x03 };
+CONST_OID secgECsect283k1[] = {SECG_OID, 0x10 };
+CONST_OID secgECsect283r1[] = {SECG_OID, 0x11 };
+CONST_OID secgECsect409k1[] = {SECG_OID, 0x24 };
+CONST_OID secgECsect409r1[] = {SECG_OID, 0x25 };
+CONST_OID secgECsect571k1[] = {SECG_OID, 0x26 };
+CONST_OID secgECsect571r1[] = {SECG_OID, 0x27 };
+
+CONST_OID seed_CBC[] = { SEED_OID, 4 };
+
+CONST_OID evIncorporationLocality[] = { EV_NAME_ATTRIBUTE, 1 };
+CONST_OID evIncorporationState[] = { EV_NAME_ATTRIBUTE, 2 };
+CONST_OID evIncorporationCountry[] = { EV_NAME_ATTRIBUTE, 3 };
+
+#define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
+#ifndef SECOID_NO_STRINGS
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext }
+#else
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, 0, mech, ext }
+#endif
+
+#if defined(NSS_ALLOW_UNSUPPORTED_CRITICAL)
+#define FAKE_SUPPORTED_CERT_EXTENSION SUPPORTED_CERT_EXTENSION
+#else
+#define FAKE_SUPPORTED_CERT_EXTENSION UNSUPPORTED_CERT_EXTENSION
+#endif
+
+/*
+ * NOTE: the order of these entries must mach the SECOidTag enum in secoidt.h!
+ */
+const static SECOidData oids[SEC_OID_TOTAL] = {
+ { { siDEROID, NULL, 0 }, SEC_OID_UNKNOWN,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( md2, SEC_OID_MD2, "MD2", CKM_MD2, INVALID_CERT_EXTENSION ),
+ OD( md4, SEC_OID_MD4,
+ "MD4", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( md5, SEC_OID_MD5, "MD5", CKM_MD5, INVALID_CERT_EXTENSION ),
+ OD( sha1, SEC_OID_SHA1, "SHA-1", CKM_SHA_1, INVALID_CERT_EXTENSION ),
+ OD( rc2cbc, SEC_OID_RC2_CBC,
+ "RC2-CBC", CKM_RC2_CBC, INVALID_CERT_EXTENSION ),
+ OD( rc4, SEC_OID_RC4, "RC4", CKM_RC4, INVALID_CERT_EXTENSION ),
+ OD( desede3cbc, SEC_OID_DES_EDE3_CBC,
+ "DES-EDE3-CBC", CKM_DES3_CBC, INVALID_CERT_EXTENSION ),
+ OD( rc5cbcpad, SEC_OID_RC5_CBC_PAD,
+ "RC5-CBCPad", CKM_RC5_CBC, INVALID_CERT_EXTENSION ),
+ OD( desecb, SEC_OID_DES_ECB,
+ "DES-ECB", CKM_DES_ECB, INVALID_CERT_EXTENSION ),
+ OD( descbc, SEC_OID_DES_CBC,
+ "DES-CBC", CKM_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( desofb, SEC_OID_DES_OFB,
+ "DES-OFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( descfb, SEC_OID_DES_CFB,
+ "DES-CFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( desmac, SEC_OID_DES_MAC,
+ "DES-MAC", CKM_DES_MAC, INVALID_CERT_EXTENSION ),
+ OD( desede, SEC_OID_DES_EDE,
+ "DES-EDE", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( isoSHAWithRSASignature, SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE,
+ "ISO SHA with RSA Signature",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs1RSAEncryption, SEC_OID_PKCS1_RSA_ENCRYPTION,
+ "PKCS #1 RSA Encryption", CKM_RSA_PKCS, INVALID_CERT_EXTENSION ),
+
+ /* the following Signing mechanisms should get new CKM_ values when
+ * values for CKM_RSA_WITH_MDX and CKM_RSA_WITH_SHA_1 get defined in
+ * PKCS #11.
+ */
+ OD( pkcs1MD2WithRSAEncryption, SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION,
+ "PKCS #1 MD2 With RSA Encryption", CKM_MD2_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1MD4WithRSAEncryption, SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION,
+ "PKCS #1 MD4 With RSA Encryption",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs1MD5WithRSAEncryption, SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
+ "PKCS #1 MD5 With RSA Encryption", CKM_MD5_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1SHA1WithRSAEncryption, SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-1 With RSA Encryption", CKM_SHA1_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+
+ OD( pkcs5PbeWithMD2AndDEScbc, SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC,
+ "PKCS #5 Password Based Encryption with MD2 and DES-CBC",
+ CKM_PBE_MD2_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs5PbeWithMD5AndDEScbc, SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC,
+ "PKCS #5 Password Based Encryption with MD5 and DES-CBC",
+ CKM_PBE_MD5_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs5PbeWithSha1AndDEScbc, SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC,
+ "PKCS #5 Password Based Encryption with SHA-1 and DES-CBC",
+ CKM_NETSCAPE_PBE_SHA1_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs7, SEC_OID_PKCS7,
+ "PKCS #7", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7Data, SEC_OID_PKCS7_DATA,
+ "PKCS #7 Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7SignedData, SEC_OID_PKCS7_SIGNED_DATA,
+ "PKCS #7 Signed Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7EnvelopedData, SEC_OID_PKCS7_ENVELOPED_DATA,
+ "PKCS #7 Enveloped Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7SignedEnvelopedData, SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA,
+ "PKCS #7 Signed And Enveloped Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7DigestedData, SEC_OID_PKCS7_DIGESTED_DATA,
+ "PKCS #7 Digested Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7EncryptedData, SEC_OID_PKCS7_ENCRYPTED_DATA,
+ "PKCS #7 Encrypted Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9EmailAddress, SEC_OID_PKCS9_EMAIL_ADDRESS,
+ "PKCS #9 Email Address",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9UnstructuredName, SEC_OID_PKCS9_UNSTRUCTURED_NAME,
+ "PKCS #9 Unstructured Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ContentType, SEC_OID_PKCS9_CONTENT_TYPE,
+ "PKCS #9 Content Type",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9MessageDigest, SEC_OID_PKCS9_MESSAGE_DIGEST,
+ "PKCS #9 Message Digest",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9SigningTime, SEC_OID_PKCS9_SIGNING_TIME,
+ "PKCS #9 Signing Time",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9CounterSignature, SEC_OID_PKCS9_COUNTER_SIGNATURE,
+ "PKCS #9 Counter Signature",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ChallengePassword, SEC_OID_PKCS9_CHALLENGE_PASSWORD,
+ "PKCS #9 Challenge Password",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9UnstructuredAddress, SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS,
+ "PKCS #9 Unstructured Address",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ExtendedCertificateAttributes,
+ SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES,
+ "PKCS #9 Extended Certificate Attributes",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9SMIMECapabilities, SEC_OID_PKCS9_SMIME_CAPABILITIES,
+ "PKCS #9 S/MIME Capabilities",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520CommonName, SEC_OID_AVA_COMMON_NAME,
+ "X520 Common Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520CountryName, SEC_OID_AVA_COUNTRY_NAME,
+ "X520 Country Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520LocalityName, SEC_OID_AVA_LOCALITY,
+ "X520 Locality Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520StateOrProvinceName, SEC_OID_AVA_STATE_OR_PROVINCE,
+ "X520 State Or Province Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520OrgName, SEC_OID_AVA_ORGANIZATION_NAME,
+ "X520 Organization Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520OrgUnitName, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
+ "X520 Organizational Unit Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520DnQualifier, SEC_OID_AVA_DN_QUALIFIER,
+ "X520 DN Qualifier", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( rfc2247DomainComponent, SEC_OID_AVA_DC,
+ "RFC 2247 Domain Component",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( nsTypeGIF, SEC_OID_NS_TYPE_GIF,
+ "GIF", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeJPEG, SEC_OID_NS_TYPE_JPEG,
+ "JPEG", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeURL, SEC_OID_NS_TYPE_URL,
+ "URL", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeHTML, SEC_OID_NS_TYPE_HTML,
+ "HTML", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeCertSeq, SEC_OID_NS_TYPE_CERT_SEQUENCE,
+ "Certificate Sequence",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertKEADSSOld, SEC_OID_MISSI_KEA_DSS_OLD,
+ "MISSI KEA and DSS Algorithm (Old)",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertDSSOld, SEC_OID_MISSI_DSS_OLD,
+ "MISSI DSS Algorithm (Old)",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertKEADSS, SEC_OID_MISSI_KEA_DSS,
+ "MISSI KEA and DSS Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertDSS, SEC_OID_MISSI_DSS,
+ "MISSI DSS Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertKEA, SEC_OID_MISSI_KEA,
+ "MISSI KEA Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertAltKEA, SEC_OID_MISSI_ALT_KEA,
+ "MISSI Alternate KEA Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* Netscape private extensions */
+ OD( nsCertExtNetscapeOK, SEC_OID_NS_CERT_EXT_NETSCAPE_OK,
+ "Netscape says this cert is OK",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsCertExtIssuerLogo, SEC_OID_NS_CERT_EXT_ISSUER_LOGO,
+ "Certificate Issuer Logo",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsCertExtSubjectLogo, SEC_OID_NS_CERT_EXT_SUBJECT_LOGO,
+ "Certificate Subject Logo",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCertType, SEC_OID_NS_CERT_EXT_CERT_TYPE,
+ "Certificate Type",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtBaseURL, SEC_OID_NS_CERT_EXT_BASE_URL,
+ "Certificate Extension Base URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtRevocationURL, SEC_OID_NS_CERT_EXT_REVOCATION_URL,
+ "Certificate Revocation URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCARevocationURL, SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL,
+ "Certificate Authority Revocation URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCACRLURL, SEC_OID_NS_CERT_EXT_CA_CRL_URL,
+ "Certificate Authority CRL Download URL",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCACertURL, SEC_OID_NS_CERT_EXT_CA_CERT_URL,
+ "Certificate Authority Certificate Download URL",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCertRenewalURL, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL,
+ "Certificate Renewal URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCAPolicyURL, SEC_OID_NS_CERT_EXT_CA_POLICY_URL,
+ "Certificate Authority Policy URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtHomepageURL, SEC_OID_NS_CERT_EXT_HOMEPAGE_URL,
+ "Certificate Homepage URL",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtEntityLogo, SEC_OID_NS_CERT_EXT_ENTITY_LOGO,
+ "Certificate Entity Logo",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtUserPicture, SEC_OID_NS_CERT_EXT_USER_PICTURE,
+ "Certificate User Picture",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtSSLServerName, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME,
+ "Certificate SSL Server Name",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtComment, SEC_OID_NS_CERT_EXT_COMMENT,
+ "Certificate Comment",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtLostPasswordURL, SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL,
+ "Lost Password URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCertRenewalTime, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME,
+ "Certificate Renewal Time",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsKeyUsageGovtApproved, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED,
+ "Strong Crypto Export Approved",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+
+
+ /* x.509 v3 certificate extensions */
+ OD( x509SubjectDirectoryAttr, SEC_OID_X509_SUBJECT_DIRECTORY_ATTR,
+ "Certificate Subject Directory Attributes",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION),
+ OD( x509SubjectKeyID, SEC_OID_X509_SUBJECT_KEY_ID,
+ "Certificate Subject Key ID",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509KeyUsage, SEC_OID_X509_KEY_USAGE,
+ "Certificate Key Usage",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509PrivateKeyUsagePeriod, SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD,
+ "Certificate Private Key Usage Period",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509SubjectAltName, SEC_OID_X509_SUBJECT_ALT_NAME,
+ "Certificate Subject Alt Name",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509IssuerAltName, SEC_OID_X509_ISSUER_ALT_NAME,
+ "Certificate Issuer Alt Name",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509BasicConstraints, SEC_OID_X509_BASIC_CONSTRAINTS,
+ "Certificate Basic Constraints",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509NameConstraints, SEC_OID_X509_NAME_CONSTRAINTS,
+ "Certificate Name Constraints",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509CRLDistPoints, SEC_OID_X509_CRL_DIST_POINTS,
+ "CRL Distribution Points",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509CertificatePolicies, SEC_OID_X509_CERTIFICATE_POLICIES,
+ "Certificate Policies",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509PolicyMappings, SEC_OID_X509_POLICY_MAPPINGS,
+ "Certificate Policy Mappings",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509PolicyConstraints, SEC_OID_X509_POLICY_CONSTRAINTS,
+ "Certificate Policy Constraints",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509AuthKeyID, SEC_OID_X509_AUTH_KEY_ID,
+ "Certificate Authority Key Identifier",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509ExtKeyUsage, SEC_OID_X509_EXT_KEY_USAGE,
+ "Extended Key Usage",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509AuthInfoAccess, SEC_OID_X509_AUTH_INFO_ACCESS,
+ "Authority Information Access",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+
+ /* x.509 v3 CRL extensions */
+ OD( x509CRLNumber, SEC_OID_X509_CRL_NUMBER,
+ "CRL Number", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509ReasonCode, SEC_OID_X509_REASON_CODE,
+ "CRL reason code", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509InvalidDate, SEC_OID_X509_INVALID_DATE,
+ "Invalid Date", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+
+ OD( x500RSAEncryption, SEC_OID_X500_RSA_ENCRYPTION,
+ "X500 RSA Encryption", CKM_RSA_X_509, INVALID_CERT_EXTENSION ),
+
+ /* added for alg 1485 */
+ OD( rfc1274Uid, SEC_OID_RFC1274_UID,
+ "RFC1274 User Id", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( rfc1274Mail, SEC_OID_RFC1274_MAIL,
+ "RFC1274 E-mail Address",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* pkcs 12 additions */
+ OD( pkcs12, SEC_OID_PKCS12,
+ "PKCS #12", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12ModeIDs, SEC_OID_PKCS12_MODE_IDS,
+ "PKCS #12 Mode IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12ESPVKIDs, SEC_OID_PKCS12_ESPVK_IDS,
+ "PKCS #12 ESPVK IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12BagIDs, SEC_OID_PKCS12_BAG_IDS,
+ "PKCS #12 Bag IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12CertBagIDs, SEC_OID_PKCS12_CERT_BAG_IDS,
+ "PKCS #12 Cert Bag IDs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12OIDs, SEC_OID_PKCS12_OIDS,
+ "PKCS #12 OIDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEIDs, SEC_OID_PKCS12_PBE_IDS,
+ "PKCS #12 PBE IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SignatureIDs, SEC_OID_PKCS12_SIGNATURE_IDS,
+ "PKCS #12 Signature IDs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12EnvelopingIDs, SEC_OID_PKCS12_ENVELOPING_IDS,
+ "PKCS #12 Enveloping IDs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PKCS8KeyShrouding, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING,
+ "PKCS #12 Key Shrouding",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12KeyBagID, SEC_OID_PKCS12_KEY_BAG_ID,
+ "PKCS #12 Key Bag ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12CertAndCRLBagID, SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
+ "PKCS #12 Cert And CRL Bag ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SecretBagID, SEC_OID_PKCS12_SECRET_BAG_ID,
+ "PKCS #12 Secret Bag ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12X509CertCRLBag, SEC_OID_PKCS12_X509_CERT_CRL_BAG,
+ "PKCS #12 X509 Cert CRL Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SDSICertBag, SEC_OID_PKCS12_SDSI_CERT_BAG,
+ "PKCS #12 SDSI Cert Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And128BitRC4,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4,
+ "PKCS #12 PBE With SHA-1 and 128 Bit RC4",
+ CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And40BitRC4,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4,
+ "PKCS #12 PBE With SHA-1 and 40 Bit RC4",
+ CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1AndTripleDESCBC,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC,
+ "PKCS #12 PBE With SHA-1 and Triple DES-CBC",
+ CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And128BitRC2CBC,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC,
+ "PKCS #12 PBE With SHA-1 and 128 Bit RC2 CBC",
+ CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And40BitRC2CBC,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC,
+ "PKCS #12 PBE With SHA-1 and 40 Bit RC2 CBC",
+ CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSAEncryptionWith128BitRC4,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4,
+ "PKCS #12 RSA Encryption with 128 Bit RC4",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSAEncryptionWith40BitRC4,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4,
+ "PKCS #12 RSA Encryption with 40 Bit RC4",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSAEncryptionWithTripleDES,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES,
+ "PKCS #12 RSA Encryption with Triple DES",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSASignatureWithSHA1Digest,
+ SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST,
+ "PKCS #12 RSA Encryption with Triple DES",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* DSA signatures */
+ OD( ansix9DSASignature, SEC_OID_ANSIX9_DSA_SIGNATURE,
+ "ANSI X9.57 DSA Signature", CKM_DSA, INVALID_CERT_EXTENSION ),
+ OD( ansix9DSASignaturewithSHA1Digest,
+ SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST,
+ "ANSI X9.57 DSA Signature with SHA-1 Digest",
+ CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+ OD( bogusDSASignaturewithSHA1Digest,
+ SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST,
+ "FORTEZZA DSA Signature with SHA-1 Digest",
+ CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+
+ /* verisign oids */
+ OD( verisignUserNotices, SEC_OID_VERISIGN_USER_NOTICES,
+ "Verisign User Notices",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* pkix oids */
+ OD( pkixCPSPointerQualifier, SEC_OID_PKIX_CPS_POINTER_QUALIFIER,
+ "PKIX CPS Pointer Qualifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixUserNoticeQualifier, SEC_OID_PKIX_USER_NOTICE_QUALIFIER,
+ "PKIX User Notice Qualifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkixOCSP, SEC_OID_PKIX_OCSP,
+ "PKIX Online Certificate Status Protocol",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPBasicResponse, SEC_OID_PKIX_OCSP_BASIC_RESPONSE,
+ "OCSP Basic Response", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPNonce, SEC_OID_PKIX_OCSP_NONCE,
+ "OCSP Nonce Extension", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPCRL, SEC_OID_PKIX_OCSP_CRL,
+ "OCSP CRL Reference Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPResponse, SEC_OID_PKIX_OCSP_RESPONSE,
+ "OCSP Response Types Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPNoCheck, SEC_OID_PKIX_OCSP_NO_CHECK,
+ "OCSP No Check Extension",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( pkixOCSPArchiveCutoff, SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF,
+ "OCSP Archive Cutoff Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPServiceLocator, SEC_OID_PKIX_OCSP_SERVICE_LOCATOR,
+ "OCSP Service Locator Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkixRegCtrlRegToken, SEC_OID_PKIX_REGCTRL_REGTOKEN,
+ "PKIX CRMF Registration Control, Registration Token",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixRegCtrlAuthenticator, SEC_OID_PKIX_REGCTRL_AUTHENTICATOR,
+ "PKIX CRMF Registration Control, Registration Authenticator",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixRegCtrlPKIPubInfo, SEC_OID_PKIX_REGCTRL_PKIPUBINFO,
+ "PKIX CRMF Registration Control, PKI Publication Info",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegCtrlPKIArchOptions,
+ SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
+ "PKIX CRMF Registration Control, PKI Archive Options",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegCtrlOldCertID, SEC_OID_PKIX_REGCTRL_OLD_CERT_ID,
+ "PKIX CRMF Registration Control, Old Certificate ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegCtrlProtEncKey, SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY,
+ "PKIX CRMF Registration Control, Protocol Encryption Key",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegInfoUTF8Pairs, SEC_OID_PKIX_REGINFO_UTF8_PAIRS,
+ "PKIX CRMF Registration Info, UTF8 Pairs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegInfoCertReq, SEC_OID_PKIX_REGINFO_CERT_REQUEST,
+ "PKIX CRMF Registration Info, Certificate Request",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageServerAuth,
+ SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
+ "TLS Web Server Authentication Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageClientAuth,
+ SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH,
+ "TLS Web Client Authentication Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageCodeSign, SEC_OID_EXT_KEY_USAGE_CODE_SIGN,
+ "Code Signing Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageEMailProtect,
+ SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT,
+ "E-Mail Protection Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageTimeStamp,
+ SEC_OID_EXT_KEY_USAGE_TIME_STAMP,
+ "Time Stamping Certifcate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixOCSPResponderExtendedKeyUsage, SEC_OID_OCSP_RESPONDER,
+ "OCSP Responder Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+
+ /* Netscape Algorithm OIDs */
+
+ OD( netscapeSMimeKEA, SEC_OID_NETSCAPE_SMIME_KEA,
+ "Netscape S/MIME KEA", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* Skipjack OID -- ### mwelch temporary */
+ OD( skipjackCBC, SEC_OID_FORTEZZA_SKIPJACK,
+ "Skipjack CBC64", CKM_SKIPJACK_CBC64, INVALID_CERT_EXTENSION ),
+
+ /* pkcs12 v2 oids */
+ OD( pkcs12V2PBEWithSha1And128BitRC4,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4,
+ "PKCS #12 V2 PBE With SHA-1 And 128 Bit RC4",
+ CKM_PBE_SHA1_RC4_128, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And40BitRC4,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4,
+ "PKCS #12 V2 PBE With SHA-1 And 40 Bit RC4",
+ CKM_PBE_SHA1_RC4_40, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And3KeyTripleDEScbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
+ "PKCS #12 V2 PBE With SHA-1 And 3KEY Triple DES-CBC",
+ CKM_PBE_SHA1_DES3_EDE_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And2KeyTripleDEScbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC,
+ "PKCS #12 V2 PBE With SHA-1 And 2KEY Triple DES-CBC",
+ CKM_PBE_SHA1_DES2_EDE_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And128BitRC2cbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC,
+ "PKCS #12 V2 PBE With SHA-1 And 128 Bit RC2 CBC",
+ CKM_PBE_SHA1_RC2_128_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And40BitRC2cbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC,
+ "PKCS #12 V2 PBE With SHA-1 And 40 Bit RC2 CBC",
+ CKM_PBE_SHA1_RC2_40_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SafeContentsID, SEC_OID_PKCS12_SAFE_CONTENTS_ID,
+ "PKCS #12 Safe Contents ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PKCS8ShroudedKeyBagID,
+ SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID,
+ "PKCS #12 Safe Contents ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1KeyBag, SEC_OID_PKCS12_V1_KEY_BAG_ID,
+ "PKCS #12 V1 Key Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1PKCS8ShroudedKeyBag,
+ SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID,
+ "PKCS #12 V1 PKCS8 Shrouded Key Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1CertBag, SEC_OID_PKCS12_V1_CERT_BAG_ID,
+ "PKCS #12 V1 Cert Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1CRLBag, SEC_OID_PKCS12_V1_CRL_BAG_ID,
+ "PKCS #12 V1 CRL Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1SecretBag, SEC_OID_PKCS12_V1_SECRET_BAG_ID,
+ "PKCS #12 V1 Secret Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1SafeContentsBag, SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
+ "PKCS #12 V1 Safe Contents Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkcs9X509Certificate, SEC_OID_PKCS9_X509_CERT,
+ "PKCS #9 X509 Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9SDSICertificate, SEC_OID_PKCS9_SDSI_CERT,
+ "PKCS #9 SDSI Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9X509CRL, SEC_OID_PKCS9_X509_CRL,
+ "PKCS #9 X509 CRL", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9FriendlyName, SEC_OID_PKCS9_FRIENDLY_NAME,
+ "PKCS #9 Friendly Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9LocalKeyID, SEC_OID_PKCS9_LOCAL_KEY_ID,
+ "PKCS #9 Local Key ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12KeyUsageAttr, SEC_OID_BOGUS_KEY_USAGE,
+ "Bogus Key Usage", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( dhPublicKey, SEC_OID_X942_DIFFIE_HELMAN_KEY,
+ "Diffie-Helman Public Key", CKM_DH_PKCS_DERIVE,
+ INVALID_CERT_EXTENSION ),
+ OD( netscapeNickname, SEC_OID_NETSCAPE_NICKNAME,
+ "Netscape Nickname", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* Cert Server specific OIDs */
+ OD( netscapeRecoveryRequest, SEC_OID_NETSCAPE_RECOVERY_REQUEST,
+ "Recovery Request OID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( nsExtAIACertRenewal, SEC_OID_CERT_RENEWAL_LOCATOR,
+ "Certificate Renewal Locator OID", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( nsExtCertScopeOfUse, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
+ "Certificate Scope-of-Use Extension", CKM_INVALID_MECHANISM,
+ SUPPORTED_CERT_EXTENSION ),
+
+ /* CMS stuff */
+ OD( cmsESDH, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN,
+ "Ephemeral-Static Diffie-Hellman", CKM_INVALID_MECHANISM /* XXX */,
+ INVALID_CERT_EXTENSION ),
+ OD( cms3DESwrap, SEC_OID_CMS_3DES_KEY_WRAP,
+ "CMS Triple DES Key Wrap", CKM_INVALID_MECHANISM /* XXX */,
+ INVALID_CERT_EXTENSION ),
+ OD( cmsRC2wrap, SEC_OID_CMS_RC2_KEY_WRAP,
+ "CMS RC2 Key Wrap", CKM_INVALID_MECHANISM /* XXX */,
+ INVALID_CERT_EXTENSION ),
+ OD( smimeEncryptionKeyPreference, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE,
+ "S/MIME Encryption Key Preference",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* AES algorithm OIDs */
+ OD( aes128_ECB, SEC_OID_AES_128_ECB,
+ "AES-128-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+ OD( aes128_CBC, SEC_OID_AES_128_CBC,
+ "AES-128-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+ OD( aes192_ECB, SEC_OID_AES_192_ECB,
+ "AES-192-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+ OD( aes192_CBC, SEC_OID_AES_192_CBC,
+ "AES-192-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+ OD( aes256_ECB, SEC_OID_AES_256_ECB,
+ "AES-256-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+ OD( aes256_CBC, SEC_OID_AES_256_CBC,
+ "AES-256-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+
+ /* More bogus DSA OIDs */
+ OD( sdn702DSASignature, SEC_OID_SDN702_DSA_SIGNATURE,
+ "SDN.702 DSA Signature", CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+
+ OD( ms_smimeEncryptionKeyPreference,
+ SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE,
+ "Microsoft S/MIME Encryption Key Preference",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( sha256, SEC_OID_SHA256, "SHA-256", CKM_SHA256, INVALID_CERT_EXTENSION),
+ OD( sha384, SEC_OID_SHA384, "SHA-384", CKM_SHA384, INVALID_CERT_EXTENSION),
+ OD( sha512, SEC_OID_SHA512, "SHA-512", CKM_SHA512, INVALID_CERT_EXTENSION),
+
+ OD( pkcs1SHA256WithRSAEncryption, SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-256 With RSA Encryption", CKM_SHA256_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1SHA384WithRSAEncryption, SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-384 With RSA Encryption", CKM_SHA384_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1SHA512WithRSAEncryption, SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-512 With RSA Encryption", CKM_SHA512_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+
+ OD( aes128_KEY_WRAP, SEC_OID_AES_128_KEY_WRAP,
+ "AES-128 Key Wrap", CKM_NSS_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+ OD( aes192_KEY_WRAP, SEC_OID_AES_192_KEY_WRAP,
+ "AES-192 Key Wrap", CKM_NSS_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+ OD( aes256_KEY_WRAP, SEC_OID_AES_256_KEY_WRAP,
+ "AES-256 Key Wrap", CKM_NSS_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+
+ /* Elliptic Curve Cryptography (ECC) OIDs */
+ OD( ansix962ECPublicKey, SEC_OID_ANSIX962_EC_PUBLIC_KEY,
+ "X9.62 elliptic curve public key", CKM_ECDH1_DERIVE,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA1Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE,
+ "X9.62 ECDSA signature with SHA-1", CKM_ECDSA_SHA1,
+ INVALID_CERT_EXTENSION ),
+
+ /* Named curves */
+
+ /* ANSI X9.62 named elliptic curves (prime field) */
+ OD( ansiX962prime192v1, SEC_OID_ANSIX962_EC_PRIME192V1,
+ "ANSI X9.62 elliptic curve prime192v1 (aka secp192r1, NIST P-192)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime192v2, SEC_OID_ANSIX962_EC_PRIME192V2,
+ "ANSI X9.62 elliptic curve prime192v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime192v3, SEC_OID_ANSIX962_EC_PRIME192V3,
+ "ANSI X9.62 elliptic curve prime192v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v1, SEC_OID_ANSIX962_EC_PRIME239V1,
+ "ANSI X9.62 elliptic curve prime239v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v2, SEC_OID_ANSIX962_EC_PRIME239V2,
+ "ANSI X9.62 elliptic curve prime239v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v3, SEC_OID_ANSIX962_EC_PRIME239V3,
+ "ANSI X9.62 elliptic curve prime239v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime256v1, SEC_OID_ANSIX962_EC_PRIME256V1,
+ "ANSI X9.62 elliptic curve prime256v1 (aka secp256r1, NIST P-256)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* SECG named elliptic curves (prime field) */
+ OD( secgECsecp112r1, SEC_OID_SECG_EC_SECP112R1,
+ "SECG elliptic curve secp112r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp112r2, SEC_OID_SECG_EC_SECP112R2,
+ "SECG elliptic curve secp112r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp128r1, SEC_OID_SECG_EC_SECP128R1,
+ "SECG elliptic curve secp128r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp128r2, SEC_OID_SECG_EC_SECP128R2,
+ "SECG elliptic curve secp128r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160k1, SEC_OID_SECG_EC_SECP160K1,
+ "SECG elliptic curve secp160k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160r1, SEC_OID_SECG_EC_SECP160R1,
+ "SECG elliptic curve secp160r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160r2, SEC_OID_SECG_EC_SECP160R2,
+ "SECG elliptic curve secp160r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp192k1, SEC_OID_SECG_EC_SECP192K1,
+ "SECG elliptic curve secp192k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp224k1, SEC_OID_SECG_EC_SECP224K1,
+ "SECG elliptic curve secp224k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp224r1, SEC_OID_SECG_EC_SECP224R1,
+ "SECG elliptic curve secp224r1 (aka NIST P-224)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp256k1, SEC_OID_SECG_EC_SECP256K1,
+ "SECG elliptic curve secp256k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp384r1, SEC_OID_SECG_EC_SECP384R1,
+ "SECG elliptic curve secp384r1 (aka NIST P-384)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp521r1, SEC_OID_SECG_EC_SECP521R1,
+ "SECG elliptic curve secp521r1 (aka NIST P-521)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* ANSI X9.62 named elliptic curves (characteristic two field) */
+ OD( ansiX962c2pnb163v1, SEC_OID_ANSIX962_EC_C2PNB163V1,
+ "ANSI X9.62 elliptic curve c2pnb163v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb163v2, SEC_OID_ANSIX962_EC_C2PNB163V2,
+ "ANSI X9.62 elliptic curve c2pnb163v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb163v3, SEC_OID_ANSIX962_EC_C2PNB163V3,
+ "ANSI X9.62 elliptic curve c2pnb163v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb176v1, SEC_OID_ANSIX962_EC_C2PNB176V1,
+ "ANSI X9.62 elliptic curve c2pnb176v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v1, SEC_OID_ANSIX962_EC_C2TNB191V1,
+ "ANSI X9.62 elliptic curve c2tnb191v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v2, SEC_OID_ANSIX962_EC_C2TNB191V2,
+ "ANSI X9.62 elliptic curve c2tnb191v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v3, SEC_OID_ANSIX962_EC_C2TNB191V3,
+ "ANSI X9.62 elliptic curve c2tnb191v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb191v4, SEC_OID_ANSIX962_EC_C2ONB191V4,
+ "ANSI X9.62 elliptic curve c2onb191v4",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb191v5, SEC_OID_ANSIX962_EC_C2ONB191V5,
+ "ANSI X9.62 elliptic curve c2onb191v5",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb208w1, SEC_OID_ANSIX962_EC_C2PNB208W1,
+ "ANSI X9.62 elliptic curve c2pnb208w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v1, SEC_OID_ANSIX962_EC_C2TNB239V1,
+ "ANSI X9.62 elliptic curve c2tnb239v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v2, SEC_OID_ANSIX962_EC_C2TNB239V2,
+ "ANSI X9.62 elliptic curve c2tnb239v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v3, SEC_OID_ANSIX962_EC_C2TNB239V3,
+ "ANSI X9.62 elliptic curve c2tnb239v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb239v4, SEC_OID_ANSIX962_EC_C2ONB239V4,
+ "ANSI X9.62 elliptic curve c2onb239v4",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb239v5, SEC_OID_ANSIX962_EC_C2ONB239V5,
+ "ANSI X9.62 elliptic curve c2onb239v5",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb272w1, SEC_OID_ANSIX962_EC_C2PNB272W1,
+ "ANSI X9.62 elliptic curve c2pnb272w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb304w1, SEC_OID_ANSIX962_EC_C2PNB304W1,
+ "ANSI X9.62 elliptic curve c2pnb304w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb359v1, SEC_OID_ANSIX962_EC_C2TNB359V1,
+ "ANSI X9.62 elliptic curve c2tnb359v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb368w1, SEC_OID_ANSIX962_EC_C2PNB368W1,
+ "ANSI X9.62 elliptic curve c2pnb368w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb431r1, SEC_OID_ANSIX962_EC_C2TNB431R1,
+ "ANSI X9.62 elliptic curve c2tnb431r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* SECG named elliptic curves (characterisitic two field) */
+ OD( secgECsect113r1, SEC_OID_SECG_EC_SECT113R1,
+ "SECG elliptic curve sect113r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect113r2, SEC_OID_SECG_EC_SECT113R2,
+ "SECG elliptic curve sect113r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect131r1, SEC_OID_SECG_EC_SECT131R1,
+ "SECG elliptic curve sect131r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect131r2, SEC_OID_SECG_EC_SECT131R2,
+ "SECG elliptic curve sect131r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect163k1, SEC_OID_SECG_EC_SECT163K1,
+ "SECG elliptic curve sect163k1 (aka NIST K-163)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect163r1, SEC_OID_SECG_EC_SECT163R1,
+ "SECG elliptic curve sect163r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect163r2, SEC_OID_SECG_EC_SECT163R2,
+ "SECG elliptic curve sect163r2 (aka NIST B-163)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect193r1, SEC_OID_SECG_EC_SECT193R1,
+ "SECG elliptic curve sect193r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect193r2, SEC_OID_SECG_EC_SECT193R2,
+ "SECG elliptic curve sect193r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect233k1, SEC_OID_SECG_EC_SECT233K1,
+ "SECG elliptic curve sect233k1 (aka NIST K-233)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect233r1, SEC_OID_SECG_EC_SECT233R1,
+ "SECG elliptic curve sect233r1 (aka NIST B-233)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect239k1, SEC_OID_SECG_EC_SECT239K1,
+ "SECG elliptic curve sect239k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect283k1, SEC_OID_SECG_EC_SECT283K1,
+ "SECG elliptic curve sect283k1 (aka NIST K-283)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect283r1, SEC_OID_SECG_EC_SECT283R1,
+ "SECG elliptic curve sect283r1 (aka NIST B-283)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect409k1, SEC_OID_SECG_EC_SECT409K1,
+ "SECG elliptic curve sect409k1 (aka NIST K-409)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect409r1, SEC_OID_SECG_EC_SECT409R1,
+ "SECG elliptic curve sect409r1 (aka NIST B-409)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect571k1, SEC_OID_SECG_EC_SECT571K1,
+ "SECG elliptic curve sect571k1 (aka NIST K-571)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect571r1, SEC_OID_SECG_EC_SECT571R1,
+ "SECG elliptic curve sect571r1 (aka NIST B-571)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( netscapeAOLScreenname, SEC_OID_NETSCAPE_AOLSCREENNAME,
+ "AOL Screenname", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( x520SurName, SEC_OID_AVA_SURNAME,
+ "X520 Title", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520SerialNumber, SEC_OID_AVA_SERIAL_NUMBER,
+ "X520 Serial Number", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520StreetAddress, SEC_OID_AVA_STREET_ADDRESS,
+ "X520 Street Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520Title, SEC_OID_AVA_TITLE,
+ "X520 Title", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520PostalAddress, SEC_OID_AVA_POSTAL_ADDRESS,
+ "X520 Postal Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520PostalCode, SEC_OID_AVA_POSTAL_CODE,
+ "X520 Postal Code", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520PostOfficeBox, SEC_OID_AVA_POST_OFFICE_BOX,
+ "X520 Post Office Box", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520GivenName, SEC_OID_AVA_GIVEN_NAME,
+ "X520 Given Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520Initials, SEC_OID_AVA_INITIALS,
+ "X520 Initials", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520GenerationQualifier, SEC_OID_AVA_GENERATION_QUALIFIER,
+ "X520 Generation Qualifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520HouseIdentifier, SEC_OID_AVA_HOUSE_IDENTIFIER,
+ "X520 House Identifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520Pseudonym, SEC_OID_AVA_PSEUDONYM,
+ "X520 Pseudonym", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* More OIDs */
+ OD( pkixCAIssuers, SEC_OID_PKIX_CA_ISSUERS,
+ "PKIX CA issuers access method",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ExtensionRequest, SEC_OID_PKCS9_EXTENSION_REQUEST,
+ "PKCS #9 Extension Request",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* more ECC Signature Oids */
+ OD( ansix962SignatureRecommended,
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST,
+ "X9.62 ECDSA signature with recommended digest", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignatureSpecified,
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST,
+ "X9.62 ECDSA signature with specified digest", CKM_ECDSA,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA224Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE,
+ "X9.62 ECDSA signature with SHA224", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA256Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE,
+ "X9.62 ECDSA signature with SHA256", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA384Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE,
+ "X9.62 ECDSA signature with SHA384", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA512Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE,
+ "X9.62 ECDSA signature with SHA512", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* More id-ce and id-pe OIDs from RFC 3280 */
+ OD( x509HoldInstructionCode, SEC_OID_X509_HOLD_INSTRUCTION_CODE,
+ "CRL Hold Instruction Code", CKM_INVALID_MECHANISM,
+ UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509DeltaCRLIndicator, SEC_OID_X509_DELTA_CRL_INDICATOR,
+ "Delta CRL Indicator", CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509IssuingDistributionPoint, SEC_OID_X509_ISSUING_DISTRIBUTION_POINT,
+ "Issuing Distribution Point", CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509CertIssuer, SEC_OID_X509_CERT_ISSUER,
+ "Certificate Issuer Extension",CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509FreshestCRL, SEC_OID_X509_FRESHEST_CRL,
+ "Freshest CRL", CKM_INVALID_MECHANISM,
+ UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509InhibitAnyPolicy, SEC_OID_X509_INHIBIT_ANY_POLICY,
+ "Inhibit Any Policy", CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509SubjectInfoAccess, SEC_OID_X509_SUBJECT_INFO_ACCESS,
+ "Subject Info Access", CKM_INVALID_MECHANISM,
+ UNSUPPORTED_CERT_EXTENSION ),
+
+ /* Camellia algorithm OIDs */
+ OD( camellia128_CBC, SEC_OID_CAMELLIA_128_CBC,
+ "CAMELLIA-128-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+ OD( camellia192_CBC, SEC_OID_CAMELLIA_192_CBC,
+ "CAMELLIA-192-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+ OD( camellia256_CBC, SEC_OID_CAMELLIA_256_CBC,
+ "CAMELLIA-256-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+
+ /* PKCS 5 v2 OIDS */
+ OD( pkcs5Pbkdf2, SEC_OID_PKCS5_PBKDF2,
+ "PKCS #5 Password Based Key Dervive Function v2 ",
+ CKM_PKCS5_PBKD2, INVALID_CERT_EXTENSION ),
+ OD( pkcs5Pbes2, SEC_OID_PKCS5_PBES2,
+ "PKCS #5 Password Based Encryption v2 ",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs5Pbmac1, SEC_OID_PKCS5_PBMAC1,
+ "PKCS #5 Password Based Authentication v1 ",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha1, SEC_OID_HMAC_SHA1, "HMAC SHA-1",
+ CKM_SHA_1_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha224, SEC_OID_HMAC_SHA224, "HMAC SHA-224",
+ CKM_SHA224_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha256, SEC_OID_HMAC_SHA256, "HMAC SHA-256",
+ CKM_SHA256_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha384, SEC_OID_HMAC_SHA384, "HMAC SHA-384",
+ CKM_SHA384_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha512, SEC_OID_HMAC_SHA512, "HMAC SHA-512",
+ CKM_SHA512_HMAC, INVALID_CERT_EXTENSION ),
+
+ /* SIA extension OIDs */
+ OD( x509SIATimeStamping, SEC_OID_PKIX_TIMESTAMPING,
+ "SIA Time Stamping", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( x509SIACaRepository, SEC_OID_PKIX_CA_REPOSITORY,
+ "SIA CA Repository", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( isoSHA1WithRSASignature, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE,
+ "ISO SHA-1 with RSA Signature",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* SEED algorithm OIDs */
+ OD( seed_CBC, SEC_OID_SEED_CBC,
+ "SEED-CBC", CKM_SEED_CBC, INVALID_CERT_EXTENSION),
+
+ OD( x509CertificatePoliciesAnyPolicy, SEC_OID_X509_ANY_POLICY,
+ "Certificate Policies AnyPolicy",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkcs1RSAOAEPEncryption, SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION,
+ "PKCS #1 RSA-OAEP Encryption", CKM_RSA_PKCS_OAEP,
+ INVALID_CERT_EXTENSION ),
+
+ OD( pkcs1MGF1, SEC_OID_PKCS1_MGF1,
+ "PKCS #1 MGF1 Mask Generation Function", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( pkcs1PSpecified, SEC_OID_PKCS1_PSPECIFIED,
+ "PKCS #1 RSA-OAEP Explicitly Specified Encoding Parameters",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkcs1RSAPSSSignature, SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
+ "PKCS #1 RSA-PSS Signature", CKM_RSA_PKCS_PSS,
+ INVALID_CERT_EXTENSION ),
+
+ OD( pkcs1SHA224WithRSAEncryption, SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-224 With RSA Encryption", CKM_SHA224_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+
+ OD( sha224, SEC_OID_SHA224, "SHA-224", CKM_SHA224, INVALID_CERT_EXTENSION),
+
+ OD( evIncorporationLocality, SEC_OID_EV_INCORPORATION_LOCALITY,
+ "Jurisdiction of Incorporation Locality Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( evIncorporationState, SEC_OID_EV_INCORPORATION_STATE,
+ "Jurisdiction of Incorporation State Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( evIncorporationCountry, SEC_OID_EV_INCORPORATION_COUNTRY,
+ "Jurisdiction of Incorporation Country Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520BusinessCategory, SEC_OID_BUSINESS_CATEGORY,
+ "Business Category",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( nistDSASignaturewithSHA224Digest,
+ SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST,
+ "DSA with SHA-224 Signature",
+ CKM_INVALID_MECHANISM /* not yet defined */, INVALID_CERT_EXTENSION),
+ OD( nistDSASignaturewithSHA256Digest,
+ SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST,
+ "DSA with SHA-256 Signature",
+ CKM_INVALID_MECHANISM /* not yet defined */, INVALID_CERT_EXTENSION),
+ OD( msExtendedKeyUsageTrustListSigning,
+ SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING,
+ "Microsoft Trust List Signing",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION )
+};
+
+/* PRIVATE EXTENDED SECOID Table
+ * This table is private. Its structure is opaque to the outside.
+ * It is indexed by the same SECOidTag as the oids table above.
+ * Every member of this struct must have accessor functions (set, get)
+ * and those functions must operate by value, not by reference.
+ * The addresses of the contents of this table must not be exposed
+ * by the accessor functions.
+ */
+typedef struct privXOidStr {
+ PRUint32 notPolicyFlags; /* ones complement of policy flags */
+} privXOid;
+
+static privXOid xOids[SEC_OID_TOTAL];
+
+/*
+ * now the dynamic table. The dynamic table gets build at init time.
+ * and conceivably gets modified if the user loads new crypto modules.
+ * All this static data, and the allocated data to which it points,
+ * is protected by a global reader/writer lock.
+ * The c language guarantees that global and static data that is not
+ * explicitly initialized will be initialized with zeros. If we
+ * initialize it with zeros, the data goes into the initialized data
+ * secment, and increases the size of the library. By leaving it
+ * uninitialized, it is allocated in BSS, and does NOT increase the
+ * library size.
+ */
+
+typedef struct dynXOidStr {
+ SECOidData data;
+ privXOid priv;
+} dynXOid;
+
+static NSSRWLock * dynOidLock;
+static PLArenaPool * dynOidPool;
+static PLHashTable * dynOidHash;
+static dynXOid ** dynOidTable; /* not in the pool */
+static int dynOidEntriesAllocated;
+static int dynOidEntriesUsed;
+
+/* Creates NSSRWLock and dynOidPool at initialization time.
+*/
+static SECStatus
+secoid_InitDynOidData(void)
+{
+ SECStatus rv = SECSuccess;
+
+ dynOidLock = NSSRWLock_New(1, "dynamic OID data");
+ if (!dynOidLock) {
+ return SECFailure; /* Error code should already be set. */
+ }
+ dynOidPool = PORT_NewArena(2048);
+ if (!dynOidPool) {
+ rv = SECFailure /* Error code should already be set. */;
+ }
+ return rv;
+}
+
+/* Add oidData to hash table. Caller holds write lock dynOidLock. */
+static SECStatus
+secoid_HashDynamicOiddata(const SECOidData * oid)
+{
+ PLHashEntry *entry;
+
+ if (!dynOidHash) {
+ dynOidHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ PL_CompareValues, NULL, NULL);
+ if ( !dynOidHash ) {
+ return SECFailure;
+ }
+ }
+
+ entry = PL_HashTableAdd( dynOidHash, &oid->oid, (void *)oid );
+ return entry ? SECSuccess : SECFailure;
+}
+
+
+/*
+ * Lookup a Dynamic OID. Dynamic OID's still change slowly, so it's
+ * cheaper to rehash the table when it changes than it is to do the loop
+ * each time.
+ */
+static SECOidData *
+secoid_FindDynamic(const SECItem *key)
+{
+ SECOidData *ret = NULL;
+
+ if (dynOidHash) {
+ NSSRWLock_LockRead(dynOidLock);
+ if (dynOidHash) { /* must check it again with lock held. */
+ ret = (SECOidData *)PL_HashTableLookup(dynOidHash, key);
+ }
+ NSSRWLock_UnlockRead(dynOidLock);
+ }
+ if (ret == NULL) {
+ PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+ }
+ return ret;
+}
+
+static dynXOid *
+secoid_FindDynamicByTag(SECOidTag tagnum)
+{
+ dynXOid *dxo = NULL;
+ int tagNumDiff;
+
+ if (tagnum < SEC_OID_TOTAL) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return NULL;
+ }
+ tagNumDiff = tagnum - SEC_OID_TOTAL;
+
+ if (dynOidTable) {
+ NSSRWLock_LockRead(dynOidLock);
+ if (dynOidTable != NULL && /* must check it again with lock held. */
+ tagNumDiff < dynOidEntriesUsed) {
+ dxo = dynOidTable[tagNumDiff];
+ }
+ NSSRWLock_UnlockRead(dynOidLock);
+ }
+ if (dxo == NULL) {
+ PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+ }
+ return dxo;
+}
+
+/*
+ * This routine is thread safe now.
+ */
+SECOidTag
+SECOID_AddEntry(const SECOidData * src)
+{
+ SECOidData * dst;
+ dynXOid **table;
+ SECOidTag ret = SEC_OID_UNKNOWN;
+ SECStatus rv;
+ int tableEntries;
+ int used;
+
+ if (!src || !src->oid.data || !src->oid.len || \
+ !src->desc || !strlen(src->desc)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return ret;
+ }
+ if (src->supportedExtension != INVALID_CERT_EXTENSION &&
+ src->supportedExtension != UNSUPPORTED_CERT_EXTENSION &&
+ src->supportedExtension != SUPPORTED_CERT_EXTENSION ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return ret;
+ }
+
+ if (!dynOidPool || !dynOidLock) {
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return ret;
+ }
+
+ NSSRWLock_LockWrite(dynOidLock);
+
+ /* We've just acquired the write lock, and now we call FindOIDTag
+ ** which will acquire and release the read lock. NSSRWLock has been
+ ** designed to allow this very case without deadlock. This approach
+ ** makes the test for the presence of the OID, and the subsequent
+ ** addition of the OID to the table a single atomic write operation.
+ */
+ ret = SECOID_FindOIDTag(&src->oid);
+ if (ret != SEC_OID_UNKNOWN) {
+ /* we could return an error here, but I chose not to do that.
+ ** This way, if we add an OID to the shared library's built in
+ ** list of OIDs in some future release, and that OID is the same
+ ** as some OID that a program has been adding, the program will
+ ** not suddenly stop working.
+ */
+ goto done;
+ }
+
+ table = dynOidTable;
+ tableEntries = dynOidEntriesAllocated;
+ used = dynOidEntriesUsed;
+
+ if (used + 1 > tableEntries) {
+ dynXOid ** newTable;
+ int newTableEntries = tableEntries + 16;
+
+ newTable = (dynXOid **)PORT_Realloc(table,
+ newTableEntries * sizeof(dynXOid *));
+ if (newTable == NULL) {
+ goto done;
+ }
+ dynOidTable = table = newTable;
+ dynOidEntriesAllocated = tableEntries = newTableEntries;
+ }
+
+ /* copy oid structure */
+ dst = (SECOidData *)PORT_ArenaZNew(dynOidPool, dynXOid);
+ if (!dst) {
+ goto done;
+ }
+ rv = SECITEM_CopyItem(dynOidPool, &dst->oid, &src->oid);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+ dst->desc = PORT_ArenaStrdup(dynOidPool, src->desc);
+ if (!dst->desc) {
+ goto done;
+ }
+ dst->offset = (SECOidTag)(used + SEC_OID_TOTAL);
+ dst->mechanism = src->mechanism;
+ dst->supportedExtension = src->supportedExtension;
+
+ rv = secoid_HashDynamicOiddata(dst);
+ if (rv == SECSuccess) {
+ table[used++] = (dynXOid *)dst;
+ dynOidEntriesUsed = used;
+ ret = dst->offset;
+ }
+done:
+ NSSRWLock_UnlockWrite(dynOidLock);
+ return ret;
+}
+
+
+/* normal static table processing */
+static PLHashTable *oidhash = NULL;
+static PLHashTable *oidmechhash = NULL;
+
+static PLHashNumber
+secoid_HashNumber(const void *key)
+{
+ return (PLHashNumber) key;
+}
+
+static void
+handleHashAlgSupport(char * envVal)
+{
+ char * myVal = PORT_Strdup(envVal); /* Get a copy we can alter */
+ char * arg = myVal;
+
+ while (arg && *arg) {
+ char * nextArg = PL_strpbrk(arg, ";");
+ PRUint32 notEnable;
+
+ if (nextArg) {
+ while (*nextArg == ';') {
+ *nextArg++ = '\0';
+ }
+ }
+ notEnable = (*arg == '-') ? NSS_USE_ALG_IN_CERT_SIGNATURE : 0;
+ if ((*arg == '+' || *arg == '-') && *++arg) {
+ int i;
+
+ for (i = 1; i < SEC_OID_TOTAL; i++) {
+ if (oids[i].desc && strstr(arg, oids[i].desc)) {
+ xOids[i].notPolicyFlags = notEnable |
+ (xOids[i].notPolicyFlags & ~NSS_USE_ALG_IN_CERT_SIGNATURE);
+ }
+ }
+ }
+ arg = nextArg;
+ }
+ PORT_Free(myVal); /* can handle NULL argument OK */
+}
+
+SECStatus
+SECOID_Init(void)
+{
+ PLHashEntry *entry;
+ const SECOidData *oid;
+ int i;
+ char * envVal;
+ volatile char c; /* force a reference that won't get optimized away */
+
+ c = __nss_util_rcsid[0] + __nss_util_sccsid[0];
+
+ if (oidhash) {
+ return SECSuccess; /* already initialized */
+ }
+
+ if (!PR_GetEnv("NSS_ALLOW_WEAK_SIGNATURE_ALG")) {
+ /* initialize any policy flags that are disabled by default */
+ xOids[SEC_OID_MD2 ].notPolicyFlags = ~0;
+ xOids[SEC_OID_MD4 ].notPolicyFlags = ~0;
+ xOids[SEC_OID_MD5 ].notPolicyFlags = ~0;
+ xOids[SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION ].notPolicyFlags = ~0;
+ xOids[SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION ].notPolicyFlags = ~0;
+ xOids[SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION ].notPolicyFlags = ~0;
+ xOids[SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC].notPolicyFlags = ~0;
+ xOids[SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC].notPolicyFlags = ~0;
+ }
+
+ envVal = PR_GetEnv("NSS_HASH_ALG_SUPPORT");
+ if (envVal)
+ handleHashAlgSupport(envVal);
+
+ if (secoid_InitDynOidData() != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /* this function should never fail */
+ return SECFailure;
+ }
+
+ oidhash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ PL_CompareValues, NULL, NULL);
+ oidmechhash = PL_NewHashTable(0, secoid_HashNumber, PL_CompareValues,
+ PL_CompareValues, NULL, NULL);
+
+ if ( !oidhash || !oidmechhash) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /*This function should never fail. */
+ return(SECFailure);
+ }
+
+ for ( i = 0; i < SEC_OID_TOTAL; i++ ) {
+ oid = &oids[i];
+
+ PORT_Assert ( oid->offset == i );
+
+ entry = PL_HashTableAdd( oidhash, &oid->oid, (void *)oid );
+ if ( entry == NULL ) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /*This function should never fail. */
+ return(SECFailure);
+ }
+
+ if ( oid->mechanism != CKM_INVALID_MECHANISM ) {
+ entry = PL_HashTableAdd( oidmechhash,
+ (void *)oid->mechanism, (void *)oid );
+ if ( entry == NULL ) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /* This function should never fail. */
+ return(SECFailure);
+ }
+ }
+ }
+
+ PORT_Assert (i == SEC_OID_TOTAL);
+
+ return(SECSuccess);
+}
+
+SECOidData *
+SECOID_FindOIDByMechanism(unsigned long mechanism)
+{
+ SECOidData *ret;
+
+ PR_ASSERT(oidhash != NULL);
+
+ ret = PL_HashTableLookupConst ( oidmechhash, (void *)mechanism);
+ if ( ret == NULL ) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ }
+
+ return (ret);
+}
+
+SECOidData *
+SECOID_FindOID(const SECItem *oid)
+{
+ SECOidData *ret;
+
+ PR_ASSERT(oidhash != NULL);
+
+ ret = PL_HashTableLookupConst ( oidhash, oid );
+ if ( ret == NULL ) {
+ ret = secoid_FindDynamic(oid);
+ if (ret == NULL) {
+ PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+ }
+ }
+
+ return(ret);
+}
+
+SECOidTag
+SECOID_FindOIDTag(const SECItem *oid)
+{
+ SECOidData *oiddata;
+
+ oiddata = SECOID_FindOID (oid);
+ if (oiddata == NULL)
+ return SEC_OID_UNKNOWN;
+
+ return oiddata->offset;
+}
+
+/* This really should return const. */
+SECOidData *
+SECOID_FindOIDByTag(SECOidTag tagnum)
+{
+ if (tagnum >= SEC_OID_TOTAL) {
+ return (SECOidData *)secoid_FindDynamicByTag(tagnum);
+ }
+
+ PORT_Assert((unsigned int)tagnum < SEC_OID_TOTAL);
+ return (SECOidData *)(&oids[tagnum]);
+}
+
+PRBool SECOID_KnownCertExtenOID (SECItem *extenOid)
+{
+ SECOidData * oidData;
+
+ oidData = SECOID_FindOID (extenOid);
+ if (oidData == (SECOidData *)NULL)
+ return (PR_FALSE);
+ return ((oidData->supportedExtension == SUPPORTED_CERT_EXTENSION) ?
+ PR_TRUE : PR_FALSE);
+}
+
+
+const char *
+SECOID_FindOIDTagDescription(SECOidTag tagnum)
+{
+ const SECOidData *oidData = SECOID_FindOIDByTag(tagnum);
+ return oidData ? oidData->desc : 0;
+}
+
+/* --------- opaque extended OID table accessor functions ---------------*/
+/*
+ * Any of these functions may return SECSuccess or SECFailure with the error
+ * code set to SEC_ERROR_UNKNOWN_OBJECT_TYPE if the SECOidTag is out of range.
+ */
+
+static privXOid *
+secoid_FindXOidByTag(SECOidTag tagnum)
+{
+ if (tagnum >= SEC_OID_TOTAL) {
+ dynXOid *dxo = secoid_FindDynamicByTag(tagnum);
+ return (dxo ? &dxo->priv : NULL);
+ }
+
+ PORT_Assert((unsigned int)tagnum < SEC_OID_TOTAL);
+ return &xOids[tagnum];
+}
+
+/* The Get function outputs the 32-bit value associated with the SECOidTag.
+ * Flags bits are the NSS_USE_ALG_ #defines in "secoidt.h".
+ * Default value for any algorithm is 0xffffffff (enabled for all purposes).
+ * No value is output if function returns SECFailure.
+ */
+SECStatus
+NSS_GetAlgorithmPolicy(SECOidTag tag, PRUint32 *pValue)
+{
+ privXOid * pxo = secoid_FindXOidByTag(tag);
+ if (!pxo)
+ return SECFailure;
+ if (!pValue) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ *pValue = ~(pxo->notPolicyFlags);
+ return SECSuccess;
+}
+
+/* The Set function modifies the stored value according to the following
+ * algorithm:
+ * policy[tag] = (policy[tag] & ~clearBits) | setBits;
+ */
+SECStatus
+NSS_SetAlgorithmPolicy(SECOidTag tag, PRUint32 setBits, PRUint32 clearBits)
+{
+ privXOid * pxo = secoid_FindXOidByTag(tag);
+ PRUint32 policyFlags;
+ if (!pxo)
+ return SECFailure;
+ /* The stored policy flags are the ones complement of the flags as
+ * seen by the user. This is not atomic, but these changes should
+ * be done rarely, e.g. at initialization time.
+ */
+ policyFlags = ~(pxo->notPolicyFlags);
+ policyFlags = (policyFlags & ~clearBits) | setBits;
+ pxo->notPolicyFlags = ~policyFlags;
+ return SECSuccess;
+}
+
+/* --------- END OF opaque extended OID table accessor functions ---------*/
+
+/* for now, this is only used in a single place, so it can remain static */
+static PRBool parentForkedAfterC_Initialize;
+
+#define SKIP_AFTER_FORK(x) if (!parentForkedAfterC_Initialize) x
+
+/*
+ * free up the oid tables.
+ */
+SECStatus
+SECOID_Shutdown(void)
+{
+ if (oidhash) {
+ PL_HashTableDestroy(oidhash);
+ oidhash = NULL;
+ }
+ if (oidmechhash) {
+ PL_HashTableDestroy(oidmechhash);
+ oidmechhash = NULL;
+ }
+ /* Have to handle the case where the lock was created, but
+ ** the pool wasn't.
+ ** I'm not going to attempt to create the lock, just to protect
+ ** the destruction of data that probably isn't initialized anyway.
+ */
+ if (dynOidLock) {
+ SKIP_AFTER_FORK(NSSRWLock_LockWrite(dynOidLock));
+ if (dynOidHash) {
+ PL_HashTableDestroy(dynOidHash);
+ dynOidHash = NULL;
+ }
+ if (dynOidPool) {
+ PORT_FreeArena(dynOidPool, PR_FALSE);
+ dynOidPool = NULL;
+ }
+ if (dynOidTable) {
+ PORT_Free(dynOidTable);
+ dynOidTable = NULL;
+ }
+ dynOidEntriesAllocated = 0;
+ dynOidEntriesUsed = 0;
+
+ SKIP_AFTER_FORK(NSSRWLock_UnlockWrite(dynOidLock));
+ SKIP_AFTER_FORK(NSSRWLock_Destroy(dynOidLock));
+ dynOidLock = NULL;
+ } else {
+ /* Since dynOidLock doesn't exist, then all the data it protects
+ ** should be uninitialized. We'll check that (in DEBUG builds),
+ ** and then make sure it is so, in case NSS is reinitialized.
+ */
+ PORT_Assert(!dynOidHash && !dynOidPool && !dynOidTable && \
+ !dynOidEntriesAllocated && !dynOidEntriesUsed);
+ dynOidHash = NULL;
+ dynOidPool = NULL;
+ dynOidTable = NULL;
+ dynOidEntriesAllocated = 0;
+ dynOidEntriesUsed = 0;
+ }
+ memset(xOids, 0, sizeof xOids);
+ return SECSuccess;
+}
+
+void UTIL_SetForkState(PRBool forked)
+{
+ parentForkedAfterC_Initialize = forked;
+}
+
+const char *
+NSSUTIL_GetVersion(void)
+{
+ return NSSUTIL_VERSION;
+}
diff --git a/lib/util/secoid.h b/lib/util/secoid.h
new file mode 100644
index 000000000..69e47a7db
--- /dev/null
+++ b/lib/util/secoid.h
@@ -0,0 +1,143 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SECOID_H_
+#define _SECOID_H_
+
+#include "utilrename.h"
+
+/*
+ * secoid.h - public data structures and prototypes for ASN.1 OID functions
+ *
+ * $Id$
+ */
+
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secasn1t.h"
+
+SEC_BEGIN_PROTOS
+
+extern const SEC_ASN1Template SECOID_AlgorithmIDTemplate[];
+
+/* This functions simply returns the address of the above-declared template. */
+SEC_ASN1_CHOOSER_DECLARE(SECOID_AlgorithmIDTemplate)
+
+/*
+ * OID handling routines
+ */
+extern SECOidData *SECOID_FindOID( const SECItem *oid);
+extern SECOidTag SECOID_FindOIDTag(const SECItem *oid);
+extern SECOidData *SECOID_FindOIDByTag(SECOidTag tagnum);
+extern SECOidData *SECOID_FindOIDByMechanism(unsigned long mechanism);
+
+/****************************************/
+/*
+** Algorithm id handling operations
+*/
+
+/*
+** Fill in an algorithm-ID object given a tag and some parameters.
+** "aid" where the DER encoded algorithm info is stored (memory
+** is allocated)
+** "tag" the tag number defining the algorithm
+** "params" if not NULL, the parameters to go with the algorithm
+*/
+extern SECStatus SECOID_SetAlgorithmID(PLArenaPool *arena, SECAlgorithmID *aid,
+ SECOidTag tag, SECItem *params);
+
+/*
+** Copy the "src" object to "dest". Memory is allocated in "dest" for
+** each of the appropriate sub-objects. Memory in "dest" is not freed
+** before memory is allocated (use SECOID_DestroyAlgorithmID(dest, PR_FALSE)
+** to do that).
+*/
+extern SECStatus SECOID_CopyAlgorithmID(PLArenaPool *arena, SECAlgorithmID *dest,
+ SECAlgorithmID *src);
+
+/*
+** Get the tag number for the given algorithm-id object.
+*/
+extern SECOidTag SECOID_GetAlgorithmTag(SECAlgorithmID *aid);
+
+/*
+** Destroy an algorithm-id object.
+** "aid" the certificate-request to destroy
+** "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void SECOID_DestroyAlgorithmID(SECAlgorithmID *aid, PRBool freeit);
+
+/*
+** Compare two algorithm-id objects, returning the difference between
+** them.
+*/
+extern SECComparison SECOID_CompareAlgorithmID(SECAlgorithmID *a,
+ SECAlgorithmID *b);
+
+extern PRBool SECOID_KnownCertExtenOID (SECItem *extenOid);
+
+/* Given a tag number, return a string describing it.
+ */
+extern const char *SECOID_FindOIDTagDescription(SECOidTag tagnum);
+
+/* Add a dynamic SECOidData to the dynamic OID table.
+** Routine copies the src entry, and returns the new SECOidTag.
+** Returns SEC_OID_INVALID if failed to add for some reason.
+*/
+extern SECOidTag SECOID_AddEntry(const SECOidData * src);
+
+/*
+ * initialize the oid data structures.
+ */
+extern SECStatus SECOID_Init(void);
+
+/*
+ * free up the oid data structures.
+ */
+extern SECStatus SECOID_Shutdown(void);
+
+/* if to->data is not NULL, and to->len is large enough to hold the result,
+ * then the resultant OID will be copyed into to->data, and to->len will be
+ * changed to show the actual OID length.
+ * Otherwise, memory for the OID will be allocated (from the caller's
+ * PLArenaPool, if pool is non-NULL) and to->data will receive the address
+ * of the allocated data, and to->len will receive the OID length.
+ * The original value of to->data is not freed when a new buffer is allocated.
+ *
+ * The input string may begin with "OID." and this still be ignored.
+ * The length of the input string is given in len. If len == 0, then
+ * len will be computed as strlen(from), meaning it must be NUL terminated.
+ * It is an error if from == NULL, or if *from == '\0'.
+ */
+extern SECStatus SEC_StringToOID(PLArenaPool *pool, SECItem *to,
+ const char *from, PRUint32 len);
+
+extern void UTIL_SetForkState(PRBool forked);
+
+/*
+ * Accessor functions for new opaque extended SECOID table.
+ * Any of these functions may return SECSuccess or SECFailure with the error
+ * code set to SEC_ERROR_UNKNOWN_OBJECT_TYPE if the SECOidTag is out of range.
+ */
+
+/* The Get function outputs the 32-bit value associated with the SECOidTag.
+ * Flags bits are the NSS_USE_ALG_ #defines in "secoidt.h".
+ * Default value for any algorithm is 0xffffffff (enabled for all purposes).
+ * No value is output if function returns SECFailure.
+ */
+extern SECStatus NSS_GetAlgorithmPolicy(SECOidTag tag, PRUint32 *pValue);
+
+/* The Set function modifies the stored value according to the following
+ * algorithm:
+ * policy[tag] = (policy[tag] & ~clearBits) | setBits;
+ */
+extern SECStatus
+NSS_SetAlgorithmPolicy(SECOidTag tag, PRUint32 setBits, PRUint32 clearBits);
+
+
+SEC_END_PROTOS
+
+#endif /* _SECOID_H_ */
diff --git a/lib/util/secoidt.h b/lib/util/secoidt.h
new file mode 100644
index 000000000..3f3b563df
--- /dev/null
+++ b/lib/util/secoidt.h
@@ -0,0 +1,486 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _SECOIDT_H_
+#define _SECOIDT_H_
+
+#include "utilrename.h"
+
+/*
+ * secoidt.h - public data structures for ASN.1 OID functions
+ *
+ * $Id$
+ */
+
+#include "secitem.h"
+
+typedef struct SECOidDataStr SECOidData;
+typedef struct SECAlgorithmIDStr SECAlgorithmID;
+
+/*
+** An X.500 algorithm identifier
+*/
+struct SECAlgorithmIDStr {
+ SECItem algorithm;
+ SECItem parameters;
+};
+
+/*
+ * Misc object IDs - these numbers are for convenient handling.
+ * They are mapped into real object IDs
+ *
+ * NOTE: the order of these entries must mach the array "oids" of SECOidData
+ * in util/secoid.c.
+ */
+typedef enum {
+ SEC_OID_UNKNOWN = 0,
+ SEC_OID_MD2 = 1,
+ SEC_OID_MD4 = 2,
+ SEC_OID_MD5 = 3,
+ SEC_OID_SHA1 = 4,
+ SEC_OID_RC2_CBC = 5,
+ SEC_OID_RC4 = 6,
+ SEC_OID_DES_EDE3_CBC = 7,
+ SEC_OID_RC5_CBC_PAD = 8,
+ SEC_OID_DES_ECB = 9,
+ SEC_OID_DES_CBC = 10,
+ SEC_OID_DES_OFB = 11,
+ SEC_OID_DES_CFB = 12,
+ SEC_OID_DES_MAC = 13,
+ SEC_OID_DES_EDE = 14,
+ SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE = 15,
+ SEC_OID_PKCS1_RSA_ENCRYPTION = 16,
+ SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION = 17,
+ SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION = 18,
+ SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION = 19,
+ SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION = 20,
+ SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC = 21,
+ SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC = 22,
+ SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC = 23,
+ SEC_OID_PKCS7 = 24,
+ SEC_OID_PKCS7_DATA = 25,
+ SEC_OID_PKCS7_SIGNED_DATA = 26,
+ SEC_OID_PKCS7_ENVELOPED_DATA = 27,
+ SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA = 28,
+ SEC_OID_PKCS7_DIGESTED_DATA = 29,
+ SEC_OID_PKCS7_ENCRYPTED_DATA = 30,
+ SEC_OID_PKCS9_EMAIL_ADDRESS = 31,
+ SEC_OID_PKCS9_UNSTRUCTURED_NAME = 32,
+ SEC_OID_PKCS9_CONTENT_TYPE = 33,
+ SEC_OID_PKCS9_MESSAGE_DIGEST = 34,
+ SEC_OID_PKCS9_SIGNING_TIME = 35,
+ SEC_OID_PKCS9_COUNTER_SIGNATURE = 36,
+ SEC_OID_PKCS9_CHALLENGE_PASSWORD = 37,
+ SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS = 38,
+ SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES = 39,
+ SEC_OID_PKCS9_SMIME_CAPABILITIES = 40,
+ SEC_OID_AVA_COMMON_NAME = 41,
+ SEC_OID_AVA_COUNTRY_NAME = 42,
+ SEC_OID_AVA_LOCALITY = 43,
+ SEC_OID_AVA_STATE_OR_PROVINCE = 44,
+ SEC_OID_AVA_ORGANIZATION_NAME = 45,
+ SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME = 46,
+ SEC_OID_AVA_DN_QUALIFIER = 47,
+ SEC_OID_AVA_DC = 48,
+
+ SEC_OID_NS_TYPE_GIF = 49,
+ SEC_OID_NS_TYPE_JPEG = 50,
+ SEC_OID_NS_TYPE_URL = 51,
+ SEC_OID_NS_TYPE_HTML = 52,
+ SEC_OID_NS_TYPE_CERT_SEQUENCE = 53,
+ SEC_OID_MISSI_KEA_DSS_OLD = 54,
+ SEC_OID_MISSI_DSS_OLD = 55,
+ SEC_OID_MISSI_KEA_DSS = 56,
+ SEC_OID_MISSI_DSS = 57,
+ SEC_OID_MISSI_KEA = 58,
+ SEC_OID_MISSI_ALT_KEA = 59,
+
+ /* Netscape private certificate extensions */
+ SEC_OID_NS_CERT_EXT_NETSCAPE_OK = 60,
+ SEC_OID_NS_CERT_EXT_ISSUER_LOGO = 61,
+ SEC_OID_NS_CERT_EXT_SUBJECT_LOGO = 62,
+ SEC_OID_NS_CERT_EXT_CERT_TYPE = 63,
+ SEC_OID_NS_CERT_EXT_BASE_URL = 64,
+ SEC_OID_NS_CERT_EXT_REVOCATION_URL = 65,
+ SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL = 66,
+ SEC_OID_NS_CERT_EXT_CA_CRL_URL = 67,
+ SEC_OID_NS_CERT_EXT_CA_CERT_URL = 68,
+ SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL = 69,
+ SEC_OID_NS_CERT_EXT_CA_POLICY_URL = 70,
+ SEC_OID_NS_CERT_EXT_HOMEPAGE_URL = 71,
+ SEC_OID_NS_CERT_EXT_ENTITY_LOGO = 72,
+ SEC_OID_NS_CERT_EXT_USER_PICTURE = 73,
+ SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME = 74,
+ SEC_OID_NS_CERT_EXT_COMMENT = 75,
+ SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL = 76,
+ SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME = 77,
+ SEC_OID_NS_KEY_USAGE_GOVT_APPROVED = 78,
+
+ /* x.509 v3 Extensions */
+ SEC_OID_X509_SUBJECT_DIRECTORY_ATTR = 79,
+ SEC_OID_X509_SUBJECT_KEY_ID = 80,
+ SEC_OID_X509_KEY_USAGE = 81,
+ SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD = 82,
+ SEC_OID_X509_SUBJECT_ALT_NAME = 83,
+ SEC_OID_X509_ISSUER_ALT_NAME = 84,
+ SEC_OID_X509_BASIC_CONSTRAINTS = 85,
+ SEC_OID_X509_NAME_CONSTRAINTS = 86,
+ SEC_OID_X509_CRL_DIST_POINTS = 87,
+ SEC_OID_X509_CERTIFICATE_POLICIES = 88,
+ SEC_OID_X509_POLICY_MAPPINGS = 89,
+ SEC_OID_X509_POLICY_CONSTRAINTS = 90,
+ SEC_OID_X509_AUTH_KEY_ID = 91,
+ SEC_OID_X509_EXT_KEY_USAGE = 92,
+ SEC_OID_X509_AUTH_INFO_ACCESS = 93,
+
+ SEC_OID_X509_CRL_NUMBER = 94,
+ SEC_OID_X509_REASON_CODE = 95,
+ SEC_OID_X509_INVALID_DATE = 96,
+ /* End of x.509 v3 Extensions */
+
+ SEC_OID_X500_RSA_ENCRYPTION = 97,
+
+ /* alg 1485 additions */
+ SEC_OID_RFC1274_UID = 98,
+ SEC_OID_RFC1274_MAIL = 99,
+
+ /* PKCS 12 additions */
+ SEC_OID_PKCS12 = 100,
+ SEC_OID_PKCS12_MODE_IDS = 101,
+ SEC_OID_PKCS12_ESPVK_IDS = 102,
+ SEC_OID_PKCS12_BAG_IDS = 103,
+ SEC_OID_PKCS12_CERT_BAG_IDS = 104,
+ SEC_OID_PKCS12_OIDS = 105,
+ SEC_OID_PKCS12_PBE_IDS = 106,
+ SEC_OID_PKCS12_SIGNATURE_IDS = 107,
+ SEC_OID_PKCS12_ENVELOPING_IDS = 108,
+ /* SEC_OID_PKCS12_OFFLINE_TRANSPORT_MODE,
+ SEC_OID_PKCS12_ONLINE_TRANSPORT_MODE, */
+ SEC_OID_PKCS12_PKCS8_KEY_SHROUDING = 109,
+ SEC_OID_PKCS12_KEY_BAG_ID = 110,
+ SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID = 111,
+ SEC_OID_PKCS12_SECRET_BAG_ID = 112,
+ SEC_OID_PKCS12_X509_CERT_CRL_BAG = 113,
+ SEC_OID_PKCS12_SDSI_CERT_BAG = 114,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4 = 115,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4 = 116,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC = 117,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 118,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 119,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4 = 120,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4 = 121,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES = 122,
+ SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST = 123,
+ /* end of PKCS 12 additions */
+
+ /* DSA signatures */
+ SEC_OID_ANSIX9_DSA_SIGNATURE = 124,
+ SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST = 125,
+ SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST = 126,
+
+ /* Verisign OIDs */
+ SEC_OID_VERISIGN_USER_NOTICES = 127,
+
+ /* PKIX OIDs */
+ SEC_OID_PKIX_CPS_POINTER_QUALIFIER = 128,
+ SEC_OID_PKIX_USER_NOTICE_QUALIFIER = 129,
+ SEC_OID_PKIX_OCSP = 130,
+ SEC_OID_PKIX_OCSP_BASIC_RESPONSE = 131,
+ SEC_OID_PKIX_OCSP_NONCE = 132,
+ SEC_OID_PKIX_OCSP_CRL = 133,
+ SEC_OID_PKIX_OCSP_RESPONSE = 134,
+ SEC_OID_PKIX_OCSP_NO_CHECK = 135,
+ SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF = 136,
+ SEC_OID_PKIX_OCSP_SERVICE_LOCATOR = 137,
+ SEC_OID_PKIX_REGCTRL_REGTOKEN = 138,
+ SEC_OID_PKIX_REGCTRL_AUTHENTICATOR = 139,
+ SEC_OID_PKIX_REGCTRL_PKIPUBINFO = 140,
+ SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS = 141,
+ SEC_OID_PKIX_REGCTRL_OLD_CERT_ID = 142,
+ SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY = 143,
+ SEC_OID_PKIX_REGINFO_UTF8_PAIRS = 144,
+ SEC_OID_PKIX_REGINFO_CERT_REQUEST = 145,
+ SEC_OID_EXT_KEY_USAGE_SERVER_AUTH = 146,
+ SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH = 147,
+ SEC_OID_EXT_KEY_USAGE_CODE_SIGN = 148,
+ SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT = 149,
+ SEC_OID_EXT_KEY_USAGE_TIME_STAMP = 150,
+ SEC_OID_OCSP_RESPONDER = 151,
+
+ /* Netscape Algorithm OIDs */
+ SEC_OID_NETSCAPE_SMIME_KEA = 152,
+
+ /* Skipjack OID -- ### mwelch temporary */
+ SEC_OID_FORTEZZA_SKIPJACK = 153,
+
+ /* PKCS 12 V2 oids */
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4 = 154,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4 = 155,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC = 156,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC = 157,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 158,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 159,
+ SEC_OID_PKCS12_SAFE_CONTENTS_ID = 160,
+ SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID = 161,
+
+ SEC_OID_PKCS12_V1_KEY_BAG_ID = 162,
+ SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID = 163,
+ SEC_OID_PKCS12_V1_CERT_BAG_ID = 164,
+ SEC_OID_PKCS12_V1_CRL_BAG_ID = 165,
+ SEC_OID_PKCS12_V1_SECRET_BAG_ID = 166,
+ SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID = 167,
+ SEC_OID_PKCS9_X509_CERT = 168,
+ SEC_OID_PKCS9_SDSI_CERT = 169,
+ SEC_OID_PKCS9_X509_CRL = 170,
+ SEC_OID_PKCS9_FRIENDLY_NAME = 171,
+ SEC_OID_PKCS9_LOCAL_KEY_ID = 172,
+ SEC_OID_BOGUS_KEY_USAGE = 173,
+
+ /*Diffe Helman OIDS */
+ SEC_OID_X942_DIFFIE_HELMAN_KEY = 174,
+
+ /* Netscape other name types */
+ /* SEC_OID_NETSCAPE_NICKNAME is an otherName field of type IA5String
+ * in the subjectAltName certificate extension. NSS dropped support
+ * for SEC_OID_NETSCAPE_NICKNAME in NSS 3.13. */
+ SEC_OID_NETSCAPE_NICKNAME = 175,
+
+ /* Cert Server OIDS */
+ SEC_OID_NETSCAPE_RECOVERY_REQUEST = 176,
+
+ /* New PSM certificate management OIDs */
+ SEC_OID_CERT_RENEWAL_LOCATOR = 177,
+ SEC_OID_NS_CERT_EXT_SCOPE_OF_USE = 178,
+
+ /* CMS (RFC2630) OIDs */
+ SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN = 179,
+ SEC_OID_CMS_3DES_KEY_WRAP = 180,
+ SEC_OID_CMS_RC2_KEY_WRAP = 181,
+
+ /* SMIME attributes */
+ SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE = 182,
+
+ /* AES OIDs */
+ SEC_OID_AES_128_ECB = 183,
+ SEC_OID_AES_128_CBC = 184,
+ SEC_OID_AES_192_ECB = 185,
+ SEC_OID_AES_192_CBC = 186,
+ SEC_OID_AES_256_ECB = 187,
+ SEC_OID_AES_256_CBC = 188,
+
+ SEC_OID_SDN702_DSA_SIGNATURE = 189,
+
+ SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE = 190,
+
+ SEC_OID_SHA256 = 191,
+ SEC_OID_SHA384 = 192,
+ SEC_OID_SHA512 = 193,
+
+ SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION = 194,
+ SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION = 195,
+ SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION = 196,
+
+ SEC_OID_AES_128_KEY_WRAP = 197,
+ SEC_OID_AES_192_KEY_WRAP = 198,
+ SEC_OID_AES_256_KEY_WRAP = 199,
+
+ /* Elliptic Curve Cryptography (ECC) OIDs */
+ SEC_OID_ANSIX962_EC_PUBLIC_KEY = 200,
+ SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE = 201,
+
+#define SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST \
+ SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE
+
+ /* ANSI X9.62 named elliptic curves (prime field) */
+ SEC_OID_ANSIX962_EC_PRIME192V1 = 202,
+ SEC_OID_ANSIX962_EC_PRIME192V2 = 203,
+ SEC_OID_ANSIX962_EC_PRIME192V3 = 204,
+ SEC_OID_ANSIX962_EC_PRIME239V1 = 205,
+ SEC_OID_ANSIX962_EC_PRIME239V2 = 206,
+ SEC_OID_ANSIX962_EC_PRIME239V3 = 207,
+ SEC_OID_ANSIX962_EC_PRIME256V1 = 208,
+
+ /* SECG named elliptic curves (prime field) */
+ SEC_OID_SECG_EC_SECP112R1 = 209,
+ SEC_OID_SECG_EC_SECP112R2 = 210,
+ SEC_OID_SECG_EC_SECP128R1 = 211,
+ SEC_OID_SECG_EC_SECP128R2 = 212,
+ SEC_OID_SECG_EC_SECP160K1 = 213,
+ SEC_OID_SECG_EC_SECP160R1 = 214,
+ SEC_OID_SECG_EC_SECP160R2 = 215,
+ SEC_OID_SECG_EC_SECP192K1 = 216,
+ /* SEC_OID_SECG_EC_SECP192R1 is SEC_OID_ANSIX962_EC_PRIME192V1 */
+ SEC_OID_SECG_EC_SECP224K1 = 217,
+ SEC_OID_SECG_EC_SECP224R1 = 218,
+ SEC_OID_SECG_EC_SECP256K1 = 219,
+ /* SEC_OID_SECG_EC_SECP256R1 is SEC_OID_ANSIX962_EC_PRIME256V1 */
+ SEC_OID_SECG_EC_SECP384R1 = 220,
+ SEC_OID_SECG_EC_SECP521R1 = 221,
+
+ /* ANSI X9.62 named elliptic curves (characteristic two field) */
+ SEC_OID_ANSIX962_EC_C2PNB163V1 = 222,
+ SEC_OID_ANSIX962_EC_C2PNB163V2 = 223,
+ SEC_OID_ANSIX962_EC_C2PNB163V3 = 224,
+ SEC_OID_ANSIX962_EC_C2PNB176V1 = 225,
+ SEC_OID_ANSIX962_EC_C2TNB191V1 = 226,
+ SEC_OID_ANSIX962_EC_C2TNB191V2 = 227,
+ SEC_OID_ANSIX962_EC_C2TNB191V3 = 228,
+ SEC_OID_ANSIX962_EC_C2ONB191V4 = 229,
+ SEC_OID_ANSIX962_EC_C2ONB191V5 = 230,
+ SEC_OID_ANSIX962_EC_C2PNB208W1 = 231,
+ SEC_OID_ANSIX962_EC_C2TNB239V1 = 232,
+ SEC_OID_ANSIX962_EC_C2TNB239V2 = 233,
+ SEC_OID_ANSIX962_EC_C2TNB239V3 = 234,
+ SEC_OID_ANSIX962_EC_C2ONB239V4 = 235,
+ SEC_OID_ANSIX962_EC_C2ONB239V5 = 236,
+ SEC_OID_ANSIX962_EC_C2PNB272W1 = 237,
+ SEC_OID_ANSIX962_EC_C2PNB304W1 = 238,
+ SEC_OID_ANSIX962_EC_C2TNB359V1 = 239,
+ SEC_OID_ANSIX962_EC_C2PNB368W1 = 240,
+ SEC_OID_ANSIX962_EC_C2TNB431R1 = 241,
+
+ /* SECG named elliptic curves (characteristic two field) */
+ SEC_OID_SECG_EC_SECT113R1 = 242,
+ SEC_OID_SECG_EC_SECT113R2 = 243,
+ SEC_OID_SECG_EC_SECT131R1 = 244,
+ SEC_OID_SECG_EC_SECT131R2 = 245,
+ SEC_OID_SECG_EC_SECT163K1 = 246,
+ SEC_OID_SECG_EC_SECT163R1 = 247,
+ SEC_OID_SECG_EC_SECT163R2 = 248,
+ SEC_OID_SECG_EC_SECT193R1 = 249,
+ SEC_OID_SECG_EC_SECT193R2 = 250,
+ SEC_OID_SECG_EC_SECT233K1 = 251,
+ SEC_OID_SECG_EC_SECT233R1 = 252,
+ SEC_OID_SECG_EC_SECT239K1 = 253,
+ SEC_OID_SECG_EC_SECT283K1 = 254,
+ SEC_OID_SECG_EC_SECT283R1 = 255,
+ SEC_OID_SECG_EC_SECT409K1 = 256,
+ SEC_OID_SECG_EC_SECT409R1 = 257,
+ SEC_OID_SECG_EC_SECT571K1 = 258,
+ SEC_OID_SECG_EC_SECT571R1 = 259,
+
+ SEC_OID_NETSCAPE_AOLSCREENNAME = 260,
+
+ SEC_OID_AVA_SURNAME = 261,
+ SEC_OID_AVA_SERIAL_NUMBER = 262,
+ SEC_OID_AVA_STREET_ADDRESS = 263,
+ SEC_OID_AVA_TITLE = 264,
+ SEC_OID_AVA_POSTAL_ADDRESS = 265,
+ SEC_OID_AVA_POSTAL_CODE = 266,
+ SEC_OID_AVA_POST_OFFICE_BOX = 267,
+ SEC_OID_AVA_GIVEN_NAME = 268,
+ SEC_OID_AVA_INITIALS = 269,
+ SEC_OID_AVA_GENERATION_QUALIFIER = 270,
+ SEC_OID_AVA_HOUSE_IDENTIFIER = 271,
+ SEC_OID_AVA_PSEUDONYM = 272,
+
+ /* More OIDs */
+ SEC_OID_PKIX_CA_ISSUERS = 273,
+ SEC_OID_PKCS9_EXTENSION_REQUEST = 274,
+
+ /* new EC Signature oids */
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST = 275,
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST = 276,
+ SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE = 277,
+ SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE = 278,
+ SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE = 279,
+ SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE = 280,
+
+ /* More id-ce and id-pe OIDs from RFC 3280 */
+ SEC_OID_X509_HOLD_INSTRUCTION_CODE = 281,
+ SEC_OID_X509_DELTA_CRL_INDICATOR = 282,
+ SEC_OID_X509_ISSUING_DISTRIBUTION_POINT = 283,
+ SEC_OID_X509_CERT_ISSUER = 284,
+ SEC_OID_X509_FRESHEST_CRL = 285,
+ SEC_OID_X509_INHIBIT_ANY_POLICY = 286,
+ SEC_OID_X509_SUBJECT_INFO_ACCESS = 287,
+
+ /* Camellia OIDs (RFC3657)*/
+ SEC_OID_CAMELLIA_128_CBC = 288,
+ SEC_OID_CAMELLIA_192_CBC = 289,
+ SEC_OID_CAMELLIA_256_CBC = 290,
+
+ /* PKCS 5 V2 OIDS */
+ SEC_OID_PKCS5_PBKDF2 = 291,
+ SEC_OID_PKCS5_PBES2 = 292,
+ SEC_OID_PKCS5_PBMAC1 = 293,
+ SEC_OID_HMAC_SHA1 = 294,
+ SEC_OID_HMAC_SHA224 = 295,
+ SEC_OID_HMAC_SHA256 = 296,
+ SEC_OID_HMAC_SHA384 = 297,
+ SEC_OID_HMAC_SHA512 = 298,
+
+ SEC_OID_PKIX_TIMESTAMPING = 299,
+ SEC_OID_PKIX_CA_REPOSITORY = 300,
+
+ SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE = 301,
+
+ SEC_OID_SEED_CBC = 302,
+
+ SEC_OID_X509_ANY_POLICY = 303,
+
+ SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION = 304,
+ SEC_OID_PKCS1_MGF1 = 305,
+ SEC_OID_PKCS1_PSPECIFIED = 306,
+ SEC_OID_PKCS1_RSA_PSS_SIGNATURE = 307,
+ SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION = 308,
+
+ SEC_OID_SHA224 = 309,
+
+ SEC_OID_EV_INCORPORATION_LOCALITY = 310,
+ SEC_OID_EV_INCORPORATION_STATE = 311,
+ SEC_OID_EV_INCORPORATION_COUNTRY = 312,
+ SEC_OID_BUSINESS_CATEGORY = 313,
+
+ SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST = 314,
+ SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST = 315,
+
+ /* Microsoft Trust List Signing
+ * szOID_KP_CTL_USAGE_SIGNING
+ * where KP stands for Key Purpose
+ */
+ SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING = 316,
+
+ SEC_OID_TOTAL
+} SECOidTag;
+
+#define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1
+#define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1
+#define SEC_OID_PKCS12_KEY_USAGE SEC_OID_X509_KEY_USAGE
+
+/* fake OID for DSS sign/verify */
+#define SEC_OID_SHA SEC_OID_MISS_DSS
+
+typedef enum {
+ INVALID_CERT_EXTENSION = 0,
+ UNSUPPORTED_CERT_EXTENSION = 1,
+ SUPPORTED_CERT_EXTENSION = 2
+} SECSupportExtenTag;
+
+struct SECOidDataStr {
+ SECItem oid;
+ SECOidTag offset;
+ const char * desc;
+ unsigned long mechanism;
+ SECSupportExtenTag supportedExtension;
+ /* only used for x.509 v3 extensions, so
+ that we can print the names of those
+ extensions that we don't even support */
+};
+
+/* New Opaque extended OID table API.
+ * These are algorithm policy Flags, used with functions
+ * NSS_SetAlgorithmPolicy & NSS_GetAlgorithmPolicy.
+ */
+#define NSS_USE_ALG_IN_CERT_SIGNATURE 0x00000001 /* CRLs and OCSP, too */
+#define NSS_USE_ALG_IN_CMS_SIGNATURE 0x00000002 /* used in S/MIME */
+#define NSS_USE_ALG_RESERVED 0xfffffffc /* may be used in future */
+
+/* Code MUST NOT SET or CLEAR reserved bits, and must NOT depend on them
+ * being all zeros or having any other known value. The reserved bits
+ * must be ignored.
+ */
+
+
+#endif /* _SECOIDT_H_ */
diff --git a/lib/util/secplcy.c b/lib/util/secplcy.c
new file mode 100644
index 000000000..3b5523408
--- /dev/null
+++ b/lib/util/secplcy.c
@@ -0,0 +1,85 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secplcy.h"
+#include "prmem.h"
+
+SECCipherFind *sec_CipherFindInit(PRBool onlyAllowed,
+ secCPStruct *policy,
+ long *ciphers)
+{
+ SECCipherFind *find = PR_NEWZAP(SECCipherFind);
+ if (find)
+ {
+ find->policy = policy;
+ find->ciphers = ciphers;
+ find->onlyAllowed = onlyAllowed;
+ find->index = -1;
+ }
+ return find;
+}
+
+long sec_CipherFindNext(SECCipherFind *find)
+{
+ char *policy;
+ long rv = -1;
+ secCPStruct *policies = (secCPStruct *) find->policy;
+ long *ciphers = (long *) find->ciphers;
+ long numCiphers = policies->num_ciphers;
+
+ find->index++;
+ while((find->index < numCiphers) && (rv == -1))
+ {
+ /* Translate index to cipher. */
+ rv = ciphers[find->index];
+
+ /* If we're only looking for allowed ciphers, and if this
+ cipher isn't allowed, loop around.*/
+ if (find->onlyAllowed)
+ {
+ /* Find the appropriate policy flag. */
+ policy = (&(policies->begin_ciphers)) + find->index + 1;
+
+ /* If this cipher isn't allowed by policy, continue. */
+ if (! (*policy))
+ {
+ rv = -1;
+ find->index++;
+ }
+ }
+ }
+
+ return rv;
+}
+
+char sec_IsCipherAllowed(long cipher, secCPStruct *policies,
+ long *ciphers)
+{
+ char result = SEC_CIPHER_NOT_ALLOWED; /* our default answer */
+ long numCiphers = policies->num_ciphers;
+ char *policy;
+ int i;
+
+ /* Convert the cipher number into a policy flag location. */
+ for (i=0, policy=(&(policies->begin_ciphers) + 1);
+ i<numCiphers;
+ i++, policy++)
+ {
+ if (cipher == ciphers[i])
+ break;
+ }
+
+ if (i < numCiphers)
+ {
+ /* Found the cipher, get the policy value. */
+ result = *policy;
+ }
+
+ return result;
+}
+
+void sec_CipherFindEnd(SECCipherFind *find)
+{
+ PR_FREEIF(find);
+}
diff --git a/lib/util/secplcy.h b/lib/util/secplcy.h
new file mode 100644
index 000000000..a34e23356
--- /dev/null
+++ b/lib/util/secplcy.h
@@ -0,0 +1,106 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __secplcy_h__
+#define __secplcy_h__
+
+#include "utilrename.h"
+
+#include "prtypes.h"
+
+/*
+** Cipher policy enforcement. This code isn't very pretty, but it accomplishes
+** the purpose of obscuring policy information from potential fortifiers. :-)
+**
+** The following routines are generic and intended for anywhere where cipher
+** policy enforcement is to be done, e.g. SSL and PKCS7&12.
+*/
+
+#define SEC_CIPHER_NOT_ALLOWED 0
+#define SEC_CIPHER_ALLOWED 1
+#define SEC_CIPHER_RESTRICTED 2 /* cipher is allowed in limited cases
+ e.g. step-up */
+
+/* The length of the header string for each cipher table.
+ (It's the same regardless of whether we're using md5 strings or not.) */
+#define SEC_POLICY_HEADER_LENGTH 48
+
+/* If we're testing policy stuff, we may want to use the plaintext version */
+#define SEC_POLICY_USE_MD5_STRINGS 1
+
+#define SEC_POLICY_THIS_IS_THE \
+ "\x2a\x3a\x51\xbf\x2f\x71\xb7\x73\xaa\xca\x6b\x57\x70\xcd\xc8\x9f"
+#define SEC_POLICY_STRING_FOR_THE \
+ "\x97\x15\xe2\x70\xd2\x8a\xde\xa9\xe7\xa7\x6a\xe2\x83\xe5\xb1\xf6"
+#define SEC_POLICY_SSL_TAIL \
+ "\x70\x16\x25\xc0\x2a\xb2\x4a\xca\xb6\x67\xb1\x89\x20\xdf\x87\xca"
+#define SEC_POLICY_SMIME_TAIL \
+ "\xdf\xd4\xe7\x2a\xeb\xc4\x1b\xb5\xd8\xe5\xe0\x2a\x16\x9f\xc4\xb9"
+#define SEC_POLICY_PKCS12_TAIL \
+ "\x1c\xf8\xa4\x85\x4a\xc6\x8a\xfe\xe6\xca\x03\x72\x50\x1c\xe2\xc8"
+
+#if defined(SEC_POLICY_USE_MD5_STRINGS)
+
+/* We're not testing.
+ Use md5 checksums of the strings. */
+
+#define SEC_POLICY_SSL_HEADER \
+ SEC_POLICY_THIS_IS_THE SEC_POLICY_STRING_FOR_THE SEC_POLICY_SSL_TAIL
+
+#define SEC_POLICY_SMIME_HEADER \
+ SEC_POLICY_THIS_IS_THE SEC_POLICY_STRING_FOR_THE SEC_POLICY_SMIME_TAIL
+
+#define SEC_POLICY_PKCS12_HEADER \
+ SEC_POLICY_THIS_IS_THE SEC_POLICY_STRING_FOR_THE SEC_POLICY_PKCS12_TAIL
+
+#else
+
+/* We're testing.
+ Use plaintext versions of the strings, for testing purposes. */
+#define SEC_POLICY_SSL_HEADER \
+ "This is the string for the SSL policy table. "
+#define SEC_POLICY_SMIME_HEADER \
+ "This is the string for the PKCS7 policy table. "
+#define SEC_POLICY_PKCS12_HEADER \
+ "This is the string for the PKCS12 policy table. "
+
+#endif
+
+/* Local cipher tables have to have these members at the top. */
+typedef struct _sec_cp_struct
+{
+ char policy_string[SEC_POLICY_HEADER_LENGTH];
+ long unused; /* placeholder for max keybits in pkcs12 struct */
+ char num_ciphers;
+ char begin_ciphers;
+ /* cipher policy settings follow. each is a char. */
+} secCPStruct;
+
+struct SECCipherFindStr
+{
+ /* (policy) and (ciphers) are opaque to the outside world */
+ void *policy;
+ void *ciphers;
+ long index;
+ PRBool onlyAllowed;
+};
+
+typedef struct SECCipherFindStr SECCipherFind;
+
+SEC_BEGIN_PROTOS
+
+SECCipherFind *sec_CipherFindInit(PRBool onlyAllowed,
+ secCPStruct *policy,
+ long *ciphers);
+
+long sec_CipherFindNext(SECCipherFind *find);
+
+char sec_IsCipherAllowed(long cipher, secCPStruct *policies,
+ long *ciphers);
+
+void sec_CipherFindEnd(SECCipherFind *find);
+
+SEC_END_PROTOS
+
+#endif /* __SECPLCY_H__ */
diff --git a/lib/util/secport.c b/lib/util/secport.c
new file mode 100644
index 000000000..2d7ad1e86
--- /dev/null
+++ b/lib/util/secport.c
@@ -0,0 +1,680 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * secport.c - portability interfaces for security libraries
+ *
+ * This file abstracts out libc functionality that libsec depends on
+ *
+ * NOTE - These are not public interfaces
+ *
+ * $Id$
+ */
+
+#include "seccomon.h"
+#include "prmem.h"
+#include "prerror.h"
+#include "plarena.h"
+#include "secerr.h"
+#include "prmon.h"
+#include "nssilock.h"
+#include "secport.h"
+#include "prenv.h"
+
+#ifdef DEBUG
+#define THREADMARK
+#endif /* DEBUG */
+
+#ifdef THREADMARK
+#include "prthread.h"
+#endif /* THREADMARK */
+
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+#include <stdlib.h>
+#else
+#include "wtypes.h"
+#endif
+
+#define SET_ERROR_CODE /* place holder for code to set PR error code. */
+
+#ifdef THREADMARK
+typedef struct threadmark_mark_str {
+ struct threadmark_mark_str *next;
+ void *mark;
+} threadmark_mark;
+
+#endif /* THREADMARK */
+
+/* The value of this magic must change each time PORTArenaPool changes. */
+#define ARENAPOOL_MAGIC 0xB8AC9BDF
+
+typedef struct PORTArenaPool_str {
+ PLArenaPool arena;
+ PRUint32 magic;
+ PRLock * lock;
+#ifdef THREADMARK
+ PRThread *marking_thread;
+ threadmark_mark *first_mark;
+#endif
+} PORTArenaPool;
+
+
+/* count of allocation failures. */
+unsigned long port_allocFailures;
+
+/* locations for registering Unicode conversion functions.
+ * XXX is this the appropriate location? or should they be
+ * moved to client/server specific locations?
+ */
+PORTCharConversionFunc ucs4Utf8ConvertFunc;
+PORTCharConversionFunc ucs2Utf8ConvertFunc;
+PORTCharConversionWSwapFunc ucs2AsciiConvertFunc;
+
+void *
+PORT_Alloc(size_t bytes)
+{
+ void *rv;
+
+ /* Always allocate a non-zero amount of bytes */
+ rv = (void *)PR_Malloc(bytes ? bytes : 1);
+ if (!rv) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ return rv;
+}
+
+void *
+PORT_Realloc(void *oldptr, size_t bytes)
+{
+ void *rv;
+
+ rv = (void *)PR_Realloc(oldptr, bytes);
+ if (!rv) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ return rv;
+}
+
+void *
+PORT_ZAlloc(size_t bytes)
+{
+ void *rv;
+
+ /* Always allocate a non-zero amount of bytes */
+ rv = (void *)PR_Calloc(1, bytes ? bytes : 1);
+ if (!rv) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ return rv;
+}
+
+void
+PORT_Free(void *ptr)
+{
+ if (ptr) {
+ PR_Free(ptr);
+ }
+}
+
+void
+PORT_ZFree(void *ptr, size_t len)
+{
+ if (ptr) {
+ memset(ptr, 0, len);
+ PR_Free(ptr);
+ }
+}
+
+char *
+PORT_Strdup(const char *str)
+{
+ size_t len = PORT_Strlen(str)+1;
+ char *newstr;
+
+ newstr = (char *)PORT_Alloc(len);
+ if (newstr) {
+ PORT_Memcpy(newstr, str, len);
+ }
+ return newstr;
+}
+
+void
+PORT_SetError(int value)
+{
+#ifdef DEBUG_jp96085
+ PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
+#endif
+ PR_SetError(value, 0);
+ return;
+}
+
+int
+PORT_GetError(void)
+{
+ return(PR_GetError());
+}
+
+/********************* Arena code follows *****************************
+ * ArenaPools are like heaps. The memory in them consists of large blocks,
+ * called arenas, which are allocated from the/a system heap. Inside an
+ * ArenaPool, the arenas are organized as if they were in a stack. Newly
+ * allocated arenas are "pushed" on that stack. When you attempt to
+ * allocate memory from an ArenaPool, the code first looks to see if there
+ * is enough unused space in the top arena on the stack to satisfy your
+ * request, and if so, your request is satisfied from that arena.
+ * Otherwise, a new arena is allocated (or taken from NSPR's list of freed
+ * arenas) and pushed on to the stack. The new arena is always big enough
+ * to satisfy the request, and is also at least a minimum size that is
+ * established at the time that the ArenaPool is created.
+ *
+ * The ArenaMark function returns the address of a marker in the arena at
+ * the top of the arena stack. It is the address of the place in the arena
+ * on the top of the arena stack from which the next block of memory will
+ * be allocated. Each ArenaPool has its own separate stack, and hence
+ * marks are only relevant to the ArenaPool from which they are gotten.
+ * Marks may be nested. That is, a thread can get a mark, and then get
+ * another mark.
+ *
+ * It is intended that all the marks in an ArenaPool may only be owned by a
+ * single thread. In DEBUG builds, this is enforced. In non-DEBUG builds,
+ * it is not. In DEBUG builds, when a thread gets a mark from an
+ * ArenaPool, no other thread may acquire a mark in that ArenaPool while
+ * that mark exists, that is, until that mark is unmarked or released.
+ * Therefore, it is important that every mark be unmarked or released when
+ * the creating thread has no further need for exclusive ownership of the
+ * right to manage the ArenaPool.
+ *
+ * The ArenaUnmark function discards the ArenaMark at the address given,
+ * and all marks nested inside that mark (that is, acquired from that same
+ * ArenaPool while that mark existed). It is an error for a thread other
+ * than the mark's creator to try to unmark it. When a thread has unmarked
+ * all its marks from an ArenaPool, then another thread is able to set
+ * marks in that ArenaPool. ArenaUnmark does not deallocate (or "pop") any
+ * memory allocated from the ArenaPool since the mark was created.
+ *
+ * ArenaRelease "pops" the stack back to the mark, deallocating all the
+ * memory allocated from the arenas in the ArenaPool since that mark was
+ * created, and removing any arenas from the ArenaPool that have no
+ * remaining active allocations when that is done. It implicitly releases
+ * any marks nested inside the mark being explicitly released. It is the
+ * only operation, other than destroying the arenapool, that potentially
+ * reduces the number of arenas on the stack. Otherwise, the stack grows
+ * until the arenapool is destroyed, at which point all the arenas are
+ * freed or returned to a "free arena list", depending on their sizes.
+ */
+PLArenaPool *
+PORT_NewArena(unsigned long chunksize)
+{
+ PORTArenaPool *pool;
+
+ pool = PORT_ZNew(PORTArenaPool);
+ if (!pool) {
+ return NULL;
+ }
+ pool->magic = ARENAPOOL_MAGIC;
+ pool->lock = PZ_NewLock(nssILockArena);
+ if (!pool->lock) {
+ ++port_allocFailures;
+ PORT_Free(pool);
+ return NULL;
+ }
+ PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
+ return(&pool->arena);
+}
+
+#define MAX_SIZE 0x7fffffffUL
+
+void *
+PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
+{
+ void *p = NULL;
+
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+
+ if (size <= 0) {
+ size = 1;
+ }
+
+ if (size > MAX_SIZE) {
+ /* you lose. */
+ } else
+ /* Is it one of ours? Assume so and check the magic */
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+#ifdef THREADMARK
+ /* Most likely one of ours. Is there a thread id? */
+ if (pool->marking_thread &&
+ pool->marking_thread != PR_GetCurrentThread() ) {
+ /* Another thread holds a mark in this arena */
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return NULL;
+ } /* tid != null */
+#endif /* THREADMARK */
+ PL_ARENA_ALLOCATE(p, arena, size);
+ PZ_Unlock(pool->lock);
+ } else {
+ PL_ARENA_ALLOCATE(p, arena, size);
+ }
+
+ if (!p) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ return(p);
+}
+
+void *
+PORT_ArenaZAlloc(PLArenaPool *arena, size_t size)
+{
+ void *p;
+
+ if (size <= 0)
+ size = 1;
+
+ p = PORT_ArenaAlloc(arena, size);
+
+ if (p) {
+ PORT_Memset(p, 0, size);
+ }
+
+ return(p);
+}
+
+/*
+ * If zero is true, zeroize the arena memory before freeing it.
+ */
+void
+PORT_FreeArena(PLArenaPool *arena, PRBool zero)
+{
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ PRLock * lock = (PRLock *)0;
+ size_t len = sizeof *arena;
+ static PRBool checkedEnv = PR_FALSE;
+ static PRBool doFreeArenaPool = PR_FALSE;
+
+ if (!pool)
+ return;
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ len = sizeof *pool;
+ lock = pool->lock;
+ PZ_Lock(lock);
+ }
+ if (!checkedEnv) {
+ /* no need for thread protection here */
+ doFreeArenaPool = (PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST") == NULL);
+ checkedEnv = PR_TRUE;
+ }
+ if (zero) {
+ PL_ClearArenaPool(arena, 0);
+ }
+ if (doFreeArenaPool) {
+ PL_FreeArenaPool(arena);
+ } else {
+ PL_FinishArenaPool(arena);
+ }
+ PORT_ZFree(arena, len);
+ if (lock) {
+ PZ_Unlock(lock);
+ PZ_DestroyLock(lock);
+ }
+}
+
+void *
+PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
+{
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ PORT_Assert(newsize >= oldsize);
+
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+ /* Do we do a THREADMARK check here? */
+ PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
+ PZ_Unlock(pool->lock);
+ } else {
+ PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
+ }
+
+ return(ptr);
+}
+
+void *
+PORT_ArenaMark(PLArenaPool *arena)
+{
+ void * result;
+
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+#ifdef THREADMARK
+ {
+ threadmark_mark *tm, **pw;
+ PRThread * currentThread = PR_GetCurrentThread();
+
+ if (! pool->marking_thread ) {
+ /* First mark */
+ pool->marking_thread = currentThread;
+ } else if (currentThread != pool->marking_thread ) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return NULL;
+ }
+
+ result = PL_ARENA_MARK(arena);
+ PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark));
+ if (!tm) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+
+ tm->mark = result;
+ tm->next = (threadmark_mark *)NULL;
+
+ pw = &pool->first_mark;
+ while( *pw ) {
+ pw = &(*pw)->next;
+ }
+
+ *pw = tm;
+ }
+#else /* THREADMARK */
+ result = PL_ARENA_MARK(arena);
+#endif /* THREADMARK */
+ PZ_Unlock(pool->lock);
+ } else {
+ /* a "pure" NSPR arena */
+ result = PL_ARENA_MARK(arena);
+ }
+ return result;
+}
+
+static void
+port_ArenaZeroAfterMark(PLArenaPool *arena, void *mark)
+{
+ PLArena *a = arena->current;
+ if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
+ /* fast path: mark falls in the current arena */
+ memset(mark, 0, a->avail - (PRUword)mark);
+ } else {
+ /* slow path: need to find the arena that mark falls in */
+ for (a = arena->first.next; a; a = a->next) {
+ PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
+ memset(mark, 0, a->avail - (PRUword)mark);
+ a = a->next;
+ break;
+ }
+ }
+ for (; a; a = a->next) {
+ PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ memset((void *)a->base, 0, a->avail - a->base);
+ }
+ }
+}
+
+static void
+port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero)
+{
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+#ifdef THREADMARK
+ {
+ threadmark_mark **pw, *tm;
+
+ if (PR_GetCurrentThread() != pool->marking_thread ) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ pw = &pool->first_mark;
+ while( *pw && (mark != (*pw)->mark) ) {
+ pw = &(*pw)->next;
+ }
+
+ if (! *pw ) {
+ /* bad mark */
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ tm = *pw;
+ *pw = (threadmark_mark *)NULL;
+
+ if (zero) {
+ port_ArenaZeroAfterMark(arena, mark);
+ }
+ PL_ARENA_RELEASE(arena, mark);
+
+ if (! pool->first_mark ) {
+ pool->marking_thread = (PRThread *)NULL;
+ }
+ }
+#else /* THREADMARK */
+ if (zero) {
+ port_ArenaZeroAfterMark(arena, mark);
+ }
+ PL_ARENA_RELEASE(arena, mark);
+#endif /* THREADMARK */
+ PZ_Unlock(pool->lock);
+ } else {
+ if (zero) {
+ port_ArenaZeroAfterMark(arena, mark);
+ }
+ PL_ARENA_RELEASE(arena, mark);
+ }
+}
+
+void
+PORT_ArenaRelease(PLArenaPool *arena, void *mark)
+{
+ port_ArenaRelease(arena, mark, PR_FALSE);
+}
+
+/*
+ * Zeroize the arena memory before releasing it.
+ */
+void
+PORT_ArenaZRelease(PLArenaPool *arena, void *mark)
+{
+ port_ArenaRelease(arena, mark, PR_TRUE);
+}
+
+void
+PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
+{
+#ifdef THREADMARK
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ threadmark_mark **pw, *tm;
+
+ PZ_Lock(pool->lock);
+
+ if (PR_GetCurrentThread() != pool->marking_thread ) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ pw = &pool->first_mark;
+ while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) {
+ pw = &(*pw)->next;
+ }
+
+ if ((threadmark_mark *)NULL == *pw ) {
+ /* bad mark */
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ tm = *pw;
+ *pw = (threadmark_mark *)NULL;
+
+ if (! pool->first_mark ) {
+ pool->marking_thread = (PRThread *)NULL;
+ }
+
+ PZ_Unlock(pool->lock);
+ }
+#endif /* THREADMARK */
+}
+
+char *
+PORT_ArenaStrdup(PLArenaPool *arena, const char *str) {
+ int len = PORT_Strlen(str)+1;
+ char *newstr;
+
+ newstr = (char*)PORT_ArenaAlloc(arena,len);
+ if (newstr) {
+ PORT_Memcpy(newstr,str,len);
+ }
+ return newstr;
+}
+
+/********************** end of arena functions ***********************/
+
+/****************** unicode conversion functions ***********************/
+/*
+ * NOTE: These conversion functions all assume that the multibyte
+ * characters are going to be in NETWORK BYTE ORDER, not host byte
+ * order. This is because the only time we deal with UCS-2 and UCS-4
+ * are when the data was received from or is going to be sent out
+ * over the wire (in, e.g. certificates).
+ */
+
+void
+PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{
+ ucs4Utf8ConvertFunc = convFunc;
+}
+
+void
+PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc)
+{
+ ucs2AsciiConvertFunc = convFunc;
+}
+
+void
+PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{
+ ucs2Utf8ConvertFunc = convFunc;
+}
+
+PRBool
+PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+ if(!ucs4Utf8ConvertFunc) {
+ return sec_port_ucs4_utf8_conversion_function(toUnicode,
+ inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
+ }
+
+ return (*ucs4Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
+ maxOutBufLen, outBufLen);
+}
+
+PRBool
+PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+ if(!ucs2Utf8ConvertFunc) {
+ return sec_port_ucs2_utf8_conversion_function(toUnicode,
+ inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
+ }
+
+ return (*ucs2Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
+ maxOutBufLen, outBufLen);
+}
+
+PRBool
+PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+ return sec_port_iso88591_utf8_conversion_function(inBuf, inBufLen,
+ outBuf, maxOutBufLen, outBufLen);
+}
+
+PRBool
+PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen,
+ PRBool swapBytes)
+{
+ if(!ucs2AsciiConvertFunc) {
+ return PR_FALSE;
+ }
+
+ return (*ucs2AsciiConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
+ maxOutBufLen, outBufLen, swapBytes);
+}
+
+
+/* Portable putenv. Creates/replaces an environment variable of the form
+ * envVarName=envValue
+ */
+int
+NSS_PutEnv(const char * envVarName, const char * envValue)
+{
+ SECStatus result = SECSuccess;
+ char * encoded;
+ int putEnvFailed;
+#ifdef _WIN32
+ PRBool setOK;
+
+ setOK = SetEnvironmentVariable(envVarName, envValue);
+ if (!setOK) {
+ SET_ERROR_CODE
+ return SECFailure;
+ }
+#endif
+
+ encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue));
+ strcpy(encoded, envVarName);
+ strcat(encoded, "=");
+ strcat(encoded, envValue);
+
+ putEnvFailed = putenv(encoded); /* adopt. */
+ if (putEnvFailed) {
+ SET_ERROR_CODE
+ result = SECFailure;
+ PORT_Free(encoded);
+ }
+ return result;
+}
+
+/*
+ * Perform a constant-time compare of two memory regions. The return value is
+ * 0 if the memory regions are equal and non-zero otherwise.
+ */
+int
+NSS_SecureMemcmp(const void *ia, const void *ib, size_t n)
+{
+ const unsigned char *a = (const unsigned char*) ia;
+ const unsigned char *b = (const unsigned char*) ib;
+ size_t i;
+ unsigned char r = 0;
+
+ for (i = 0; i < n; ++i) {
+ r |= *a++ ^ *b++;
+ }
+
+ return r;
+}
diff --git a/lib/util/secport.h b/lib/util/secport.h
new file mode 100644
index 000000000..af0c6a82d
--- /dev/null
+++ b/lib/util/secport.h
@@ -0,0 +1,252 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * secport.h - portability interfaces for security libraries
+ *
+ * $Id$
+ */
+
+#ifndef _SECPORT_H_
+#define _SECPORT_H_
+
+#include "utilrename.h"
+#include "prlink.h"
+
+/*
+ * define XP_WIN, XP_BEOS, or XP_UNIX, in case they are not defined
+ * by anyone else
+ */
+#ifdef _WINDOWS
+# ifndef XP_WIN
+# define XP_WIN
+# endif
+#if defined(_WIN32) || defined(WIN32)
+# ifndef XP_WIN32
+# define XP_WIN32
+# endif
+#endif
+#endif
+
+#ifdef __BEOS__
+# ifndef XP_BEOS
+# define XP_BEOS
+# endif
+#endif
+
+#ifdef unix
+# ifndef XP_UNIX
+# define XP_UNIX
+# endif
+#endif
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "prtypes.h"
+#include "prlog.h" /* for PR_ASSERT */
+#include "plarena.h"
+#include "plstr.h"
+
+/*
+ * HACK for NSS 2.8 to allow Admin to compile without source changes.
+ */
+#ifndef SEC_BEGIN_PROTOS
+#include "seccomon.h"
+#endif
+
+SEC_BEGIN_PROTOS
+
+extern void *PORT_Alloc(size_t len);
+extern void *PORT_Realloc(void *old, size_t len);
+extern void *PORT_AllocBlock(size_t len);
+extern void *PORT_ReallocBlock(void *old, size_t len);
+extern void PORT_FreeBlock(void *ptr);
+extern void *PORT_ZAlloc(size_t len);
+extern void PORT_Free(void *ptr);
+extern void PORT_ZFree(void *ptr, size_t len);
+extern char *PORT_Strdup(const char *s);
+extern time_t PORT_Time(void);
+extern void PORT_SetError(int value);
+extern int PORT_GetError(void);
+
+extern PLArenaPool *PORT_NewArena(unsigned long chunksize);
+extern void *PORT_ArenaAlloc(PLArenaPool *arena, size_t size);
+extern void *PORT_ArenaZAlloc(PLArenaPool *arena, size_t size);
+extern void PORT_FreeArena(PLArenaPool *arena, PRBool zero);
+extern void *PORT_ArenaGrow(PLArenaPool *arena, void *ptr,
+ size_t oldsize, size_t newsize);
+extern void *PORT_ArenaMark(PLArenaPool *arena);
+extern void PORT_ArenaRelease(PLArenaPool *arena, void *mark);
+extern void PORT_ArenaZRelease(PLArenaPool *arena, void *mark);
+extern void PORT_ArenaUnmark(PLArenaPool *arena, void *mark);
+extern char *PORT_ArenaStrdup(PLArenaPool *arena, const char *str);
+
+SEC_END_PROTOS
+
+#define PORT_Assert PR_ASSERT
+#define PORT_ZNew(type) (type*)PORT_ZAlloc(sizeof(type))
+#define PORT_New(type) (type*)PORT_Alloc(sizeof(type))
+#define PORT_ArenaNew(poolp, type) \
+ (type*) PORT_ArenaAlloc(poolp, sizeof(type))
+#define PORT_ArenaZNew(poolp, type) \
+ (type*) PORT_ArenaZAlloc(poolp, sizeof(type))
+#define PORT_NewArray(type, num) \
+ (type*) PORT_Alloc (sizeof(type)*(num))
+#define PORT_ZNewArray(type, num) \
+ (type*) PORT_ZAlloc (sizeof(type)*(num))
+#define PORT_ArenaNewArray(poolp, type, num) \
+ (type*) PORT_ArenaAlloc (poolp, sizeof(type)*(num))
+#define PORT_ArenaZNewArray(poolp, type, num) \
+ (type*) PORT_ArenaZAlloc (poolp, sizeof(type)*(num))
+
+/* Please, keep these defines sorted alphabetically. Thanks! */
+
+#define PORT_Atoi(buff) (int)strtol(buff, NULL, 10)
+
+/* Returns a UTF-8 encoded constant error string for err.
+ * Returns NULL if initialization of the error tables fails
+ * due to insufficient memory.
+ *
+ * This string must not be modified by the application.
+ */
+#define PORT_ErrorToString(err) PR_ErrorToString((err), PR_LANGUAGE_I_DEFAULT)
+
+#define PORT_ErrorToName PR_ErrorToName
+
+#define PORT_Memcmp memcmp
+#define PORT_Memcpy memcpy
+#ifndef SUNOS4
+#define PORT_Memmove memmove
+#else /*SUNOS4*/
+#define PORT_Memmove(s,ct,n) bcopy ((ct), (s), (n))
+#endif/*SUNOS4*/
+#define PORT_Memset memset
+
+#define PORT_Strcasecmp PL_strcasecmp
+#define PORT_Strcat strcat
+#define PORT_Strchr strchr
+#define PORT_Strrchr strrchr
+#define PORT_Strcmp strcmp
+#define PORT_Strcpy strcpy
+#define PORT_Strlen(s) strlen(s)
+#define PORT_Strncasecmp PL_strncasecmp
+#define PORT_Strncat strncat
+#define PORT_Strncmp strncmp
+#define PORT_Strncpy strncpy
+#define PORT_Strpbrk strpbrk
+#define PORT_Strstr strstr
+#define PORT_Strtok strtok
+
+#define PORT_Tolower tolower
+
+typedef PRBool (PR_CALLBACK * PORTCharConversionWSwapFunc) (PRBool toUnicode,
+ unsigned char *inBuf, unsigned int inBufLen,
+ unsigned char *outBuf, unsigned int maxOutBufLen,
+ unsigned int *outBufLen, PRBool swapBytes);
+
+typedef PRBool (PR_CALLBACK * PORTCharConversionFunc) (PRBool toUnicode,
+ unsigned char *inBuf, unsigned int inBufLen,
+ unsigned char *outBuf, unsigned int maxOutBufLen,
+ unsigned int *outBufLen);
+
+SEC_BEGIN_PROTOS
+
+void PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc);
+void PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc);
+PRBool PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen);
+PRBool PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen,
+ PRBool swapBytes);
+void PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc);
+PRBool PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen);
+
+/* One-way conversion from ISO-8859-1 to UTF-8 */
+PRBool PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen);
+
+extern PRBool
+sec_port_ucs4_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+);
+
+extern PRBool
+sec_port_ucs2_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+);
+
+/* One-way conversion from ISO-8859-1 to UTF-8 */
+extern PRBool
+sec_port_iso88591_utf8_conversion_function
+(
+ const unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+);
+
+extern int NSS_PutEnv(const char * envVarName, const char * envValue);
+
+extern int NSS_SecureMemcmp(const void *a, const void *b, size_t n);
+
+/*
+ * Load a shared library called "newShLibName" in the same directory as
+ * a shared library that is already loaded, called existingShLibName.
+ * A pointer to a static function in that shared library,
+ * staticShLibFunc, is required.
+ *
+ * existingShLibName:
+ * The file name of the shared library that shall be used as the
+ * "reference library". The loader will attempt to load the requested
+ * library from the same directory as the reference library.
+ *
+ * staticShLibFunc:
+ * Pointer to a static function in the "reference library".
+ *
+ * newShLibName:
+ * The simple file name of the new shared library to be loaded.
+ *
+ * We use PR_GetLibraryFilePathname to get the pathname of the loaded
+ * shared lib that contains this function, and then do a
+ * PR_LoadLibraryWithFlags with an absolute pathname for the shared
+ * library to be loaded.
+ *
+ * On Windows, the "alternate search path" strategy is employed, if available.
+ * On Unix, if existingShLibName is a symbolic link, and no link exists for the
+ * new library, the original link will be resolved, and the new library loaded
+ * from the resolved location.
+ *
+ * If the new shared library is not found in the same location as the reference
+ * library, it will then be loaded from the normal system library path.
+ */
+PRLibrary *
+PORT_LoadLibraryFromOrigin(const char* existingShLibName,
+ PRFuncPtr staticShLibFunc,
+ const char *newShLibName);
+
+SEC_END_PROTOS
+
+#endif /* _SECPORT_H_ */
diff --git a/lib/util/sectime.c b/lib/util/sectime.c
new file mode 100644
index 000000000..a0045f4c7
--- /dev/null
+++ b/lib/util/sectime.c
@@ -0,0 +1,161 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prtime.h"
+#include "secder.h"
+#include "secitem.h"
+#include "secerr.h"
+
+static char *DecodeUTCTime2FormattedAscii (SECItem *utcTimeDER, char *format);
+static char *DecodeGeneralizedTime2FormattedAscii (SECItem *generalizedTimeDER, char *format);
+
+/* convert DER utc time to ascii time string */
+char *
+DER_UTCTimeToAscii(SECItem *utcTime)
+{
+ return (DecodeUTCTime2FormattedAscii (utcTime, "%a %b %d %H:%M:%S %Y"));
+}
+
+/* convert DER utc time to ascii time string, only include day, not time */
+char *
+DER_UTCDayToAscii(SECItem *utctime)
+{
+ return (DecodeUTCTime2FormattedAscii (utctime, "%a %b %d, %Y"));
+}
+
+/* convert DER generalized time to ascii time string, only include day,
+ not time */
+char *
+DER_GeneralizedDayToAscii(SECItem *gentime)
+{
+ return (DecodeGeneralizedTime2FormattedAscii (gentime, "%a %b %d, %Y"));
+}
+
+/* convert DER generalized or UTC time to ascii time string, only include
+ day, not time */
+char *
+DER_TimeChoiceDayToAscii(SECItem *timechoice)
+{
+ switch (timechoice->type) {
+
+ case siUTCTime:
+ return DER_UTCDayToAscii(timechoice);
+
+ case siGeneralizedTime:
+ return DER_GeneralizedDayToAscii(timechoice);
+
+ default:
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+}
+
+char *
+CERT_UTCTime2FormattedAscii (int64 utcTime, char *format)
+{
+ PRExplodedTime printableTime;
+ char *timeString;
+
+ /* Converse time to local time and decompose it into components */
+ PR_ExplodeTime(utcTime, PR_LocalTimeParameters, &printableTime);
+
+ timeString = (char *)PORT_Alloc(256);
+
+ if ( timeString ) {
+ if ( ! PR_FormatTime( timeString, 256, format, &printableTime )) {
+ PORT_Free(timeString);
+ timeString = NULL;
+ }
+ }
+
+ return (timeString);
+}
+
+char *CERT_GenTime2FormattedAscii (int64 genTime, char *format)
+{
+ PRExplodedTime printableTime;
+ char *timeString;
+
+ /* Decompose time into components */
+ PR_ExplodeTime(genTime, PR_GMTParameters, &printableTime);
+
+ timeString = (char *)PORT_Alloc(256);
+
+ if ( timeString ) {
+ if ( ! PR_FormatTime( timeString, 256, format, &printableTime )) {
+ PORT_Free(timeString);
+ timeString = NULL;
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ }
+ }
+
+ return (timeString);
+}
+
+
+/* convert DER utc time to ascii time string, The format of the time string
+ depends on the input "format"
+ */
+static char *
+DecodeUTCTime2FormattedAscii (SECItem *utcTimeDER, char *format)
+{
+ int64 utcTime;
+ int rv;
+
+ rv = DER_UTCTimeToTime(&utcTime, utcTimeDER);
+ if (rv) {
+ return(NULL);
+ }
+ return (CERT_UTCTime2FormattedAscii (utcTime, format));
+}
+
+/* convert DER utc time to ascii time string, The format of the time string
+ depends on the input "format"
+ */
+static char *
+DecodeGeneralizedTime2FormattedAscii (SECItem *generalizedTimeDER, char *format)
+{
+ PRTime generalizedTime;
+ int rv;
+
+ rv = DER_GeneralizedTimeToTime(&generalizedTime, generalizedTimeDER);
+ if (rv) {
+ return(NULL);
+ }
+ return (CERT_GeneralizedTime2FormattedAscii (generalizedTime, format));
+}
+
+/* decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME
+ or a SEC_ASN1_UTC_TIME */
+
+SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input)
+{
+ switch (input->type) {
+ case siGeneralizedTime:
+ return DER_GeneralizedTimeToTime(output, input);
+
+ case siUTCTime:
+ return DER_UTCTimeToTime(output, input);
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ PORT_Assert(0);
+ return SECFailure;
+ }
+}
+
+/* encode a PRTime to an ASN.1 DER SECItem containing either a
+ SEC_ASN1_GENERALIZED_TIME or a SEC_ASN1_UTC_TIME */
+
+SECStatus DER_EncodeTimeChoice(PRArenaPool* arena, SECItem* output, PRTime input)
+{
+ SECStatus rv;
+
+ rv = DER_TimeToUTCTimeArena(arena, output, input);
+ if (rv == SECSuccess || PORT_GetError() != SEC_ERROR_INVALID_ARGS) {
+ return rv;
+ }
+ return DER_TimeToGeneralizedTimeArena(arena, output, input);
+}
diff --git a/lib/util/templates.c b/lib/util/templates.c
new file mode 100644
index 000000000..e5f1ebc24
--- /dev/null
+++ b/lib/util/templates.c
@@ -0,0 +1,136 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Templates that are compiled and exported from both libnss3 and libnssutil3.
+ * They have to be, because they were previously exported from libnss3, and
+ * there is no way to create data forwarder symbols on Unix.
+ *
+ * Please do not add to this file. New shared templates should be exported
+ * from libnssutil3 only.
+ *
+ */
+
+#include "utilrename.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "secoid.h"
+#include "secdig.h"
+
+const SEC_ASN1Template SECOID_AlgorithmIDTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SECAlgorithmID) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(SECAlgorithmID,algorithm), },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+ offsetof(SECAlgorithmID,parameters), },
+ { 0, }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SECOID_AlgorithmIDTemplate)
+
+const SEC_ASN1Template SEC_AnyTemplate[] = {
+ { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_AnyTemplate)
+
+const SEC_ASN1Template SEC_BMPStringTemplate[] = {
+ { SEC_ASN1_BMP_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BMPStringTemplate)
+
+const SEC_ASN1Template SEC_BitStringTemplate[] = {
+ { SEC_ASN1_BIT_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BitStringTemplate)
+
+const SEC_ASN1Template SEC_BooleanTemplate[] = {
+ { SEC_ASN1_BOOLEAN, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BooleanTemplate)
+
+const SEC_ASN1Template SEC_GeneralizedTimeTemplate[] = {
+ { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_GeneralizedTimeTemplate)
+
+const SEC_ASN1Template SEC_IA5StringTemplate[] = {
+ { SEC_ASN1_IA5_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_IA5StringTemplate)
+
+const SEC_ASN1Template SEC_IntegerTemplate[] = {
+ { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_IntegerTemplate)
+
+const SEC_ASN1Template SEC_NullTemplate[] = {
+ { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_NullTemplate)
+
+const SEC_ASN1Template SEC_ObjectIDTemplate[] = {
+ { SEC_ASN1_OBJECT_ID, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_ObjectIDTemplate)
+
+const SEC_ASN1Template SEC_OctetStringTemplate[] = {
+ { SEC_ASN1_OCTET_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_OctetStringTemplate)
+
+const SEC_ASN1Template SEC_PointerToAnyTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_AnyTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToAnyTemplate)
+
+const SEC_ASN1Template SEC_PointerToOctetStringTemplate[] = {
+ { SEC_ASN1_POINTER | SEC_ASN1_MAY_STREAM, 0, SEC_OctetStringTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToOctetStringTemplate)
+
+const SEC_ASN1Template SEC_SetOfAnyTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_AnyTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SetOfAnyTemplate)
+
+const SEC_ASN1Template SEC_UTCTimeTemplate[] = {
+ { SEC_ASN1_UTC_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UTCTimeTemplate)
+
+const SEC_ASN1Template SEC_UTF8StringTemplate[] = {
+ { SEC_ASN1_UTF8_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UTF8StringTemplate)
+
+/* XXX See comment below about SGN_DecodeDigestInfo -- keep this static! */
+/* XXX Changed from static -- need to change name? */
+const SEC_ASN1Template sgn_DigestInfoTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SGNDigestInfo) },
+ { SEC_ASN1_INLINE,
+ offsetof(SGNDigestInfo,digestAlgorithm),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(SGNDigestInfo,digest) },
+ { 0 }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(sgn_DigestInfoTemplate)
diff --git a/lib/util/utf8.c b/lib/util/utf8.c
new file mode 100644
index 000000000..117d8b335
--- /dev/null
+++ b/lib/util/utf8.c
@@ -0,0 +1,1800 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$";
+#endif /* DEBUG */
+
+#include "seccomon.h"
+#include "secport.h"
+
+#ifdef TEST_UTF8
+#include <assert.h>
+#undef PORT_Assert
+#define PORT_Assert assert
+#endif
+
+/*
+ * From RFC 2044:
+ *
+ * UCS-4 range (hex.) UTF-8 octet sequence (binary)
+ * 0000 0000-0000 007F 0xxxxxxx
+ * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
+ * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
+ * 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx
+ */
+
+/*
+ * From http://www.imc.org/draft-hoffman-utf16
+ *
+ * For U on [0x00010000,0x0010FFFF]: Let U' = U - 0x00010000
+ *
+ * U' = yyyyyyyyyyxxxxxxxxxx
+ * W1 = 110110yyyyyyyyyy
+ * W2 = 110111xxxxxxxxxx
+ */
+
+/*
+ * This code is assuming NETWORK BYTE ORDER for the 16- and 32-bit
+ * character values. If you wish to use this code for working with
+ * host byte order values, define the following:
+ *
+ * #if IS_BIG_ENDIAN
+ * #define L_0 0
+ * #define L_1 1
+ * #define L_2 2
+ * #define L_3 3
+ * #define H_0 0
+ * #define H_1 1
+ * #else / * not everyone has elif * /
+ * #if IS_LITTLE_ENDIAN
+ * #define L_0 3
+ * #define L_1 2
+ * #define L_2 1
+ * #define L_3 0
+ * #define H_0 1
+ * #define H_1 0
+ * #else
+ * #error "PDP and NUXI support deferred"
+ * #endif / * IS_LITTLE_ENDIAN * /
+ * #endif / * IS_BIG_ENDIAN * /
+ */
+
+#define L_0 0
+#define L_1 1
+#define L_2 2
+#define L_3 3
+#define H_0 0
+#define H_1 1
+
+#define BAD_UTF8 ((PRUint32)-1)
+
+/*
+ * Parse a single UTF-8 character per the spec. in section 3.9 (D36)
+ * of Unicode 4.0.0.
+ *
+ * Parameters:
+ * index - Points to the byte offset in inBuf of character to read. On success,
+ * updated to the offset of the following character.
+ * inBuf - Input buffer, UTF-8 encoded
+ * inbufLen - Length of input buffer, in bytes.
+ *
+ * Returns:
+ * Success - The UCS4 encoded character
+ * Failure - BAD_UTF8
+ */
+static PRUint32
+sec_port_read_utf8(unsigned int *index, unsigned char *inBuf, unsigned int inBufLen)
+{
+ PRUint32 result;
+ unsigned int i = *index;
+ int bytes_left;
+ PRUint32 min_value;
+
+ PORT_Assert(i < inBufLen);
+
+ if ( (inBuf[i] & 0x80) == 0x00 ) {
+ result = inBuf[i++];
+ bytes_left = 0;
+ min_value = 0;
+ } else if ( (inBuf[i] & 0xE0) == 0xC0 ) {
+ result = inBuf[i++] & 0x1F;
+ bytes_left = 1;
+ min_value = 0x80;
+ } else if ( (inBuf[i] & 0xF0) == 0xE0) {
+ result = inBuf[i++] & 0x0F;
+ bytes_left = 2;
+ min_value = 0x800;
+ } else if ( (inBuf[i] & 0xF8) == 0xF0) {
+ result = inBuf[i++] & 0x07;
+ bytes_left = 3;
+ min_value = 0x10000;
+ } else {
+ return BAD_UTF8;
+ }
+
+ while (bytes_left--) {
+ if (i >= inBufLen || (inBuf[i] & 0xC0) != 0x80) return BAD_UTF8;
+ result = (result << 6) | (inBuf[i++] & 0x3F);
+ }
+
+ /* Check for overlong sequences, surrogates, and outside unicode range */
+ if (result < min_value || (result & 0xFFFFF800) == 0xD800 || result > 0x10FFFF) {
+ return BAD_UTF8;
+ }
+
+ *index = i;
+ return result;
+}
+
+PRBool
+sec_port_ucs4_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+)
+{
+ PORT_Assert((unsigned int *)NULL != outBufLen);
+
+ if( toUnicode ) {
+ unsigned int i, len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ if( (inBuf[i] & 0x80) == 0x00 ) i += 1;
+ else if( (inBuf[i] & 0xE0) == 0xC0 ) i += 2;
+ else if( (inBuf[i] & 0xF0) == 0xE0 ) i += 3;
+ else if( (inBuf[i] & 0xF8) == 0xF0 ) i += 4;
+ else return PR_FALSE;
+
+ len += 4;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ PRUint32 ucs4 = sec_port_read_utf8(&i, inBuf, inBufLen);
+
+ if (ucs4 == BAD_UTF8) return PR_FALSE;
+
+ outBuf[len+L_0] = 0x00;
+ outBuf[len+L_1] = (unsigned char)(ucs4 >> 16);
+ outBuf[len+L_2] = (unsigned char)(ucs4 >> 8);
+ outBuf[len+L_3] = (unsigned char)ucs4;
+
+ len += 4;
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ } else {
+ unsigned int i, len = 0;
+ PORT_Assert((inBufLen % 4) == 0);
+ if ((inBufLen % 4) != 0) {
+ *outBufLen = 0;
+ return PR_FALSE;
+ }
+
+ for( i = 0; i < inBufLen; i += 4 ) {
+ if( (inBuf[i+L_0] > 0x00) || (inBuf[i+L_1] > 0x10) ) {
+ *outBufLen = 0;
+ return PR_FALSE;
+ } else if( inBuf[i+L_1] >= 0x01 ) len += 4;
+ else if( inBuf[i+L_2] >= 0x08 ) len += 3;
+ else if( (inBuf[i+L_2] > 0x00) || (inBuf[i+L_3] >= 0x80) ) len += 2;
+ else len += 1;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; i += 4 ) {
+ if( inBuf[i+L_1] >= 0x01 ) {
+ /* 0001 0000-001F FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ /* 00000000 000abcde fghijklm nopqrstu ->
+ 11110abc 10defghi 10jklmno 10pqrstu */
+
+ outBuf[len+0] = 0xF0 | ((inBuf[i+L_1] & 0x1C) >> 2);
+ outBuf[len+1] = 0x80 | ((inBuf[i+L_1] & 0x03) << 4)
+ | ((inBuf[i+L_2] & 0xF0) >> 4);
+ outBuf[len+2] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2)
+ | ((inBuf[i+L_3] & 0xC0) >> 6);
+ outBuf[len+3] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+ len += 4;
+ } else if( inBuf[i+L_2] >= 0x08 ) {
+ /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
+ /* 00000000 00000000 abcdefgh ijklmnop ->
+ 1110abcd 10efghij 10klmnop */
+
+ outBuf[len+0] = 0xE0 | ((inBuf[i+L_2] & 0xF0) >> 4);
+ outBuf[len+1] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2)
+ | ((inBuf[i+L_3] & 0xC0) >> 6);
+ outBuf[len+2] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+ len += 3;
+ } else if( (inBuf[i+L_2] > 0x00) || (inBuf[i+L_3] >= 0x80) ) {
+ /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */
+ /* 00000000 00000000 00000abc defghijk ->
+ 110abcde 10fghijk */
+
+ outBuf[len+0] = 0xC0 | ((inBuf[i+L_2] & 0x07) << 2)
+ | ((inBuf[i+L_3] & 0xC0) >> 6);
+ outBuf[len+1] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+ len += 2;
+ } else {
+ /* 0000 0000-0000 007F -> 0xxxxxx */
+ /* 00000000 00000000 00000000 0abcdefg ->
+ 0abcdefg */
+
+ outBuf[len+0] = (inBuf[i+L_3] & 0x7F);
+
+ len += 1;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ }
+}
+
+PRBool
+sec_port_ucs2_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+)
+{
+ PORT_Assert((unsigned int *)NULL != outBufLen);
+
+ if( toUnicode ) {
+ unsigned int i, len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ if( (inBuf[i] & 0x80) == 0x00 ) {
+ i += 1;
+ len += 2;
+ } else if( (inBuf[i] & 0xE0) == 0xC0 ) {
+ i += 2;
+ len += 2;
+ } else if( (inBuf[i] & 0xF0) == 0xE0 ) {
+ i += 3;
+ len += 2;
+ } else if( (inBuf[i] & 0xF8) == 0xF0 ) {
+ i += 4;
+ len += 4;
+ } else return PR_FALSE;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ PRUint32 ucs4 = sec_port_read_utf8(&i, inBuf, inBufLen);
+
+ if (ucs4 == BAD_UTF8) return PR_FALSE;
+
+ if( ucs4 < 0x10000) {
+ outBuf[len+H_0] = (unsigned char)(ucs4 >> 8);
+ outBuf[len+H_1] = (unsigned char)ucs4;
+ len += 2;
+ } else {
+ ucs4 -= 0x10000;
+ outBuf[len+0+H_0] = (unsigned char)(0xD8 | ((ucs4 >> 18) & 0x3));
+ outBuf[len+0+H_1] = (unsigned char)(ucs4 >> 10);
+ outBuf[len+2+H_0] = (unsigned char)(0xDC | ((ucs4 >> 8) & 0x3));
+ outBuf[len+2+H_1] = (unsigned char)ucs4;
+ len += 4;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ } else {
+ unsigned int i, len = 0;
+ PORT_Assert((inBufLen % 2) == 0);
+ if ((inBufLen % 2) != 0) {
+ *outBufLen = 0;
+ return PR_FALSE;
+ }
+
+ for( i = 0; i < inBufLen; i += 2 ) {
+ if( (inBuf[i+H_0] == 0x00) && ((inBuf[i+H_0] & 0x80) == 0x00) ) len += 1;
+ else if( inBuf[i+H_0] < 0x08 ) len += 2;
+ else if( ((inBuf[i+0+H_0] & 0xDC) == 0xD8) ) {
+ if( ((inBuf[i+2+H_0] & 0xDC) == 0xDC) && ((inBufLen - i) > 2) ) {
+ i += 2;
+ len += 4;
+ } else {
+ return PR_FALSE;
+ }
+ }
+ else len += 3;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; i += 2 ) {
+ if( (inBuf[i+H_0] == 0x00) && ((inBuf[i+H_1] & 0x80) == 0x00) ) {
+ /* 0000-007F -> 0xxxxxx */
+ /* 00000000 0abcdefg -> 0abcdefg */
+
+ outBuf[len] = inBuf[i+H_1] & 0x7F;
+
+ len += 1;
+ } else if( inBuf[i+H_0] < 0x08 ) {
+ /* 0080-07FF -> 110xxxxx 10xxxxxx */
+ /* 00000abc defghijk -> 110abcde 10fghijk */
+
+ outBuf[len+0] = 0xC0 | ((inBuf[i+H_0] & 0x07) << 2)
+ | ((inBuf[i+H_1] & 0xC0) >> 6);
+ outBuf[len+1] = 0x80 | ((inBuf[i+H_1] & 0x3F) >> 0);
+
+ len += 2;
+ } else if( (inBuf[i+H_0] & 0xDC) == 0xD8 ) {
+ int abcde, BCDE;
+
+ PORT_Assert(((inBuf[i+2+H_0] & 0xDC) == 0xDC) && ((inBufLen - i) > 2));
+
+ /* D800-DBFF DC00-DFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ /* 110110BC DEfghijk 110111lm nopqrstu ->
+ { Let abcde = BCDE + 1 }
+ 11110abc 10defghi 10jklmno 10pqrstu */
+
+ BCDE = ((inBuf[i+H_0] & 0x03) << 2) | ((inBuf[i+H_1] & 0xC0) >> 6);
+ abcde = BCDE + 1;
+
+ outBuf[len+0] = 0xF0 | ((abcde & 0x1C) >> 2);
+ outBuf[len+1] = 0x80 | ((abcde & 0x03) << 4)
+ | ((inBuf[i+0+H_1] & 0x3C) >> 2);
+ outBuf[len+2] = 0x80 | ((inBuf[i+0+H_1] & 0x03) << 4)
+ | ((inBuf[i+2+H_0] & 0x03) << 2)
+ | ((inBuf[i+2+H_1] & 0xC0) >> 6);
+ outBuf[len+3] = 0x80 | ((inBuf[i+2+H_1] & 0x3F) >> 0);
+
+ i += 2;
+ len += 4;
+ } else {
+ /* 0800-FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
+ /* abcdefgh ijklmnop -> 1110abcd 10efghij 10klmnop */
+
+ outBuf[len+0] = 0xE0 | ((inBuf[i+H_0] & 0xF0) >> 4);
+ outBuf[len+1] = 0x80 | ((inBuf[i+H_0] & 0x0F) << 2)
+ | ((inBuf[i+H_1] & 0xC0) >> 6);
+ outBuf[len+2] = 0x80 | ((inBuf[i+H_1] & 0x3F) >> 0);
+
+ len += 3;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ }
+}
+
+PRBool
+sec_port_iso88591_utf8_conversion_function
+(
+ const unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+)
+{
+ unsigned int i, len = 0;
+
+ PORT_Assert((unsigned int *)NULL != outBufLen);
+
+ for( i = 0; i < inBufLen; i++) {
+ if( (inBuf[i] & 0x80) == 0x00 ) len += 1;
+ else len += 2;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; i++) {
+ if( (inBuf[i] & 0x80) == 0x00 ) {
+ /* 00-7F -> 0xxxxxxx */
+ /* 0abcdefg -> 0abcdefg */
+
+ outBuf[len] = inBuf[i];
+ len += 1;
+ } else {
+ /* 80-FF <- 110xxxxx 10xxxxxx */
+ /* 00000000 abcdefgh -> 110000ab 10cdefgh */
+
+ outBuf[len+0] = 0xC0 | ((inBuf[i] & 0xC0) >> 6);
+ outBuf[len+1] = 0x80 | ((inBuf[i] & 0x3F) >> 0);
+
+ len += 2;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+}
+
+#ifdef TEST_UTF8
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h> /* for htonl and htons */
+
+/*
+ * UCS-4 vectors
+ */
+
+struct ucs4 {
+ PRUint32 c;
+ char *utf8;
+};
+
+/*
+ * UCS-2 vectors
+ */
+
+struct ucs2 {
+ PRUint16 c;
+ char *utf8;
+};
+
+/*
+ * UTF-16 vectors
+ */
+
+struct utf16 {
+ PRUint32 c;
+ PRUint16 w[2];
+};
+
+
+/*
+ * UCS-4 vectors
+ */
+
+struct ucs4 ucs4[] = {
+ { 0x00000001, "\x01" },
+ { 0x00000002, "\x02" },
+ { 0x00000003, "\x03" },
+ { 0x00000004, "\x04" },
+ { 0x00000007, "\x07" },
+ { 0x00000008, "\x08" },
+ { 0x0000000F, "\x0F" },
+ { 0x00000010, "\x10" },
+ { 0x0000001F, "\x1F" },
+ { 0x00000020, "\x20" },
+ { 0x0000003F, "\x3F" },
+ { 0x00000040, "\x40" },
+ { 0x0000007F, "\x7F" },
+
+ { 0x00000080, "\xC2\x80" },
+ { 0x00000081, "\xC2\x81" },
+ { 0x00000082, "\xC2\x82" },
+ { 0x00000084, "\xC2\x84" },
+ { 0x00000088, "\xC2\x88" },
+ { 0x00000090, "\xC2\x90" },
+ { 0x000000A0, "\xC2\xA0" },
+ { 0x000000C0, "\xC3\x80" },
+ { 0x000000FF, "\xC3\xBF" },
+ { 0x00000100, "\xC4\x80" },
+ { 0x00000101, "\xC4\x81" },
+ { 0x00000102, "\xC4\x82" },
+ { 0x00000104, "\xC4\x84" },
+ { 0x00000108, "\xC4\x88" },
+ { 0x00000110, "\xC4\x90" },
+ { 0x00000120, "\xC4\xA0" },
+ { 0x00000140, "\xC5\x80" },
+ { 0x00000180, "\xC6\x80" },
+ { 0x000001FF, "\xC7\xBF" },
+ { 0x00000200, "\xC8\x80" },
+ { 0x00000201, "\xC8\x81" },
+ { 0x00000202, "\xC8\x82" },
+ { 0x00000204, "\xC8\x84" },
+ { 0x00000208, "\xC8\x88" },
+ { 0x00000210, "\xC8\x90" },
+ { 0x00000220, "\xC8\xA0" },
+ { 0x00000240, "\xC9\x80" },
+ { 0x00000280, "\xCA\x80" },
+ { 0x00000300, "\xCC\x80" },
+ { 0x000003FF, "\xCF\xBF" },
+ { 0x00000400, "\xD0\x80" },
+ { 0x00000401, "\xD0\x81" },
+ { 0x00000402, "\xD0\x82" },
+ { 0x00000404, "\xD0\x84" },
+ { 0x00000408, "\xD0\x88" },
+ { 0x00000410, "\xD0\x90" },
+ { 0x00000420, "\xD0\xA0" },
+ { 0x00000440, "\xD1\x80" },
+ { 0x00000480, "\xD2\x80" },
+ { 0x00000500, "\xD4\x80" },
+ { 0x00000600, "\xD8\x80" },
+ { 0x000007FF, "\xDF\xBF" },
+
+ { 0x00000800, "\xE0\xA0\x80" },
+ { 0x00000801, "\xE0\xA0\x81" },
+ { 0x00000802, "\xE0\xA0\x82" },
+ { 0x00000804, "\xE0\xA0\x84" },
+ { 0x00000808, "\xE0\xA0\x88" },
+ { 0x00000810, "\xE0\xA0\x90" },
+ { 0x00000820, "\xE0\xA0\xA0" },
+ { 0x00000840, "\xE0\xA1\x80" },
+ { 0x00000880, "\xE0\xA2\x80" },
+ { 0x00000900, "\xE0\xA4\x80" },
+ { 0x00000A00, "\xE0\xA8\x80" },
+ { 0x00000C00, "\xE0\xB0\x80" },
+ { 0x00000FFF, "\xE0\xBF\xBF" },
+ { 0x00001000, "\xE1\x80\x80" },
+ { 0x00001001, "\xE1\x80\x81" },
+ { 0x00001002, "\xE1\x80\x82" },
+ { 0x00001004, "\xE1\x80\x84" },
+ { 0x00001008, "\xE1\x80\x88" },
+ { 0x00001010, "\xE1\x80\x90" },
+ { 0x00001020, "\xE1\x80\xA0" },
+ { 0x00001040, "\xE1\x81\x80" },
+ { 0x00001080, "\xE1\x82\x80" },
+ { 0x00001100, "\xE1\x84\x80" },
+ { 0x00001200, "\xE1\x88\x80" },
+ { 0x00001400, "\xE1\x90\x80" },
+ { 0x00001800, "\xE1\xA0\x80" },
+ { 0x00001FFF, "\xE1\xBF\xBF" },
+ { 0x00002000, "\xE2\x80\x80" },
+ { 0x00002001, "\xE2\x80\x81" },
+ { 0x00002002, "\xE2\x80\x82" },
+ { 0x00002004, "\xE2\x80\x84" },
+ { 0x00002008, "\xE2\x80\x88" },
+ { 0x00002010, "\xE2\x80\x90" },
+ { 0x00002020, "\xE2\x80\xA0" },
+ { 0x00002040, "\xE2\x81\x80" },
+ { 0x00002080, "\xE2\x82\x80" },
+ { 0x00002100, "\xE2\x84\x80" },
+ { 0x00002200, "\xE2\x88\x80" },
+ { 0x00002400, "\xE2\x90\x80" },
+ { 0x00002800, "\xE2\xA0\x80" },
+ { 0x00003000, "\xE3\x80\x80" },
+ { 0x00003FFF, "\xE3\xBF\xBF" },
+ { 0x00004000, "\xE4\x80\x80" },
+ { 0x00004001, "\xE4\x80\x81" },
+ { 0x00004002, "\xE4\x80\x82" },
+ { 0x00004004, "\xE4\x80\x84" },
+ { 0x00004008, "\xE4\x80\x88" },
+ { 0x00004010, "\xE4\x80\x90" },
+ { 0x00004020, "\xE4\x80\xA0" },
+ { 0x00004040, "\xE4\x81\x80" },
+ { 0x00004080, "\xE4\x82\x80" },
+ { 0x00004100, "\xE4\x84\x80" },
+ { 0x00004200, "\xE4\x88\x80" },
+ { 0x00004400, "\xE4\x90\x80" },
+ { 0x00004800, "\xE4\xA0\x80" },
+ { 0x00005000, "\xE5\x80\x80" },
+ { 0x00006000, "\xE6\x80\x80" },
+ { 0x00007FFF, "\xE7\xBF\xBF" },
+ { 0x00008000, "\xE8\x80\x80" },
+ { 0x00008001, "\xE8\x80\x81" },
+ { 0x00008002, "\xE8\x80\x82" },
+ { 0x00008004, "\xE8\x80\x84" },
+ { 0x00008008, "\xE8\x80\x88" },
+ { 0x00008010, "\xE8\x80\x90" },
+ { 0x00008020, "\xE8\x80\xA0" },
+ { 0x00008040, "\xE8\x81\x80" },
+ { 0x00008080, "\xE8\x82\x80" },
+ { 0x00008100, "\xE8\x84\x80" },
+ { 0x00008200, "\xE8\x88\x80" },
+ { 0x00008400, "\xE8\x90\x80" },
+ { 0x00008800, "\xE8\xA0\x80" },
+ { 0x00009000, "\xE9\x80\x80" },
+ { 0x0000A000, "\xEA\x80\x80" },
+ { 0x0000C000, "\xEC\x80\x80" },
+ { 0x0000FFFF, "\xEF\xBF\xBF" },
+
+ { 0x00010000, "\xF0\x90\x80\x80" },
+ { 0x00010001, "\xF0\x90\x80\x81" },
+ { 0x00010002, "\xF0\x90\x80\x82" },
+ { 0x00010004, "\xF0\x90\x80\x84" },
+ { 0x00010008, "\xF0\x90\x80\x88" },
+ { 0x00010010, "\xF0\x90\x80\x90" },
+ { 0x00010020, "\xF0\x90\x80\xA0" },
+ { 0x00010040, "\xF0\x90\x81\x80" },
+ { 0x00010080, "\xF0\x90\x82\x80" },
+ { 0x00010100, "\xF0\x90\x84\x80" },
+ { 0x00010200, "\xF0\x90\x88\x80" },
+ { 0x00010400, "\xF0\x90\x90\x80" },
+ { 0x00010800, "\xF0\x90\xA0\x80" },
+ { 0x00011000, "\xF0\x91\x80\x80" },
+ { 0x00012000, "\xF0\x92\x80\x80" },
+ { 0x00014000, "\xF0\x94\x80\x80" },
+ { 0x00018000, "\xF0\x98\x80\x80" },
+ { 0x0001FFFF, "\xF0\x9F\xBF\xBF" },
+ { 0x00020000, "\xF0\xA0\x80\x80" },
+ { 0x00020001, "\xF0\xA0\x80\x81" },
+ { 0x00020002, "\xF0\xA0\x80\x82" },
+ { 0x00020004, "\xF0\xA0\x80\x84" },
+ { 0x00020008, "\xF0\xA0\x80\x88" },
+ { 0x00020010, "\xF0\xA0\x80\x90" },
+ { 0x00020020, "\xF0\xA0\x80\xA0" },
+ { 0x00020040, "\xF0\xA0\x81\x80" },
+ { 0x00020080, "\xF0\xA0\x82\x80" },
+ { 0x00020100, "\xF0\xA0\x84\x80" },
+ { 0x00020200, "\xF0\xA0\x88\x80" },
+ { 0x00020400, "\xF0\xA0\x90\x80" },
+ { 0x00020800, "\xF0\xA0\xA0\x80" },
+ { 0x00021000, "\xF0\xA1\x80\x80" },
+ { 0x00022000, "\xF0\xA2\x80\x80" },
+ { 0x00024000, "\xF0\xA4\x80\x80" },
+ { 0x00028000, "\xF0\xA8\x80\x80" },
+ { 0x00030000, "\xF0\xB0\x80\x80" },
+ { 0x0003FFFF, "\xF0\xBF\xBF\xBF" },
+ { 0x00040000, "\xF1\x80\x80\x80" },
+ { 0x00040001, "\xF1\x80\x80\x81" },
+ { 0x00040002, "\xF1\x80\x80\x82" },
+ { 0x00040004, "\xF1\x80\x80\x84" },
+ { 0x00040008, "\xF1\x80\x80\x88" },
+ { 0x00040010, "\xF1\x80\x80\x90" },
+ { 0x00040020, "\xF1\x80\x80\xA0" },
+ { 0x00040040, "\xF1\x80\x81\x80" },
+ { 0x00040080, "\xF1\x80\x82\x80" },
+ { 0x00040100, "\xF1\x80\x84\x80" },
+ { 0x00040200, "\xF1\x80\x88\x80" },
+ { 0x00040400, "\xF1\x80\x90\x80" },
+ { 0x00040800, "\xF1\x80\xA0\x80" },
+ { 0x00041000, "\xF1\x81\x80\x80" },
+ { 0x00042000, "\xF1\x82\x80\x80" },
+ { 0x00044000, "\xF1\x84\x80\x80" },
+ { 0x00048000, "\xF1\x88\x80\x80" },
+ { 0x00050000, "\xF1\x90\x80\x80" },
+ { 0x00060000, "\xF1\xA0\x80\x80" },
+ { 0x0007FFFF, "\xF1\xBF\xBF\xBF" },
+ { 0x00080000, "\xF2\x80\x80\x80" },
+ { 0x00080001, "\xF2\x80\x80\x81" },
+ { 0x00080002, "\xF2\x80\x80\x82" },
+ { 0x00080004, "\xF2\x80\x80\x84" },
+ { 0x00080008, "\xF2\x80\x80\x88" },
+ { 0x00080010, "\xF2\x80\x80\x90" },
+ { 0x00080020, "\xF2\x80\x80\xA0" },
+ { 0x00080040, "\xF2\x80\x81\x80" },
+ { 0x00080080, "\xF2\x80\x82\x80" },
+ { 0x00080100, "\xF2\x80\x84\x80" },
+ { 0x00080200, "\xF2\x80\x88\x80" },
+ { 0x00080400, "\xF2\x80\x90\x80" },
+ { 0x00080800, "\xF2\x80\xA0\x80" },
+ { 0x00081000, "\xF2\x81\x80\x80" },
+ { 0x00082000, "\xF2\x82\x80\x80" },
+ { 0x00084000, "\xF2\x84\x80\x80" },
+ { 0x00088000, "\xF2\x88\x80\x80" },
+ { 0x00090000, "\xF2\x90\x80\x80" },
+ { 0x000A0000, "\xF2\xA0\x80\x80" },
+ { 0x000C0000, "\xF3\x80\x80\x80" },
+ { 0x000FFFFF, "\xF3\xBF\xBF\xBF" },
+ { 0x00100000, "\xF4\x80\x80\x80" },
+ { 0x00100001, "\xF4\x80\x80\x81" },
+ { 0x00100002, "\xF4\x80\x80\x82" },
+ { 0x00100004, "\xF4\x80\x80\x84" },
+ { 0x00100008, "\xF4\x80\x80\x88" },
+ { 0x00100010, "\xF4\x80\x80\x90" },
+ { 0x00100020, "\xF4\x80\x80\xA0" },
+ { 0x00100040, "\xF4\x80\x81\x80" },
+ { 0x00100080, "\xF4\x80\x82\x80" },
+ { 0x00100100, "\xF4\x80\x84\x80" },
+ { 0x00100200, "\xF4\x80\x88\x80" },
+ { 0x00100400, "\xF4\x80\x90\x80" },
+ { 0x00100800, "\xF4\x80\xA0\x80" },
+ { 0x00101000, "\xF4\x81\x80\x80" },
+ { 0x00102000, "\xF4\x82\x80\x80" },
+ { 0x00104000, "\xF4\x84\x80\x80" },
+ { 0x00108000, "\xF4\x88\x80\x80" },
+ { 0x0010FFFF, "\xF4\x8F\xBF\xBF" },
+};
+
+/*
+ * UCS-2 vectors
+ */
+
+struct ucs2 ucs2[] = {
+ { 0x0001, "\x01" },
+ { 0x0002, "\x02" },
+ { 0x0003, "\x03" },
+ { 0x0004, "\x04" },
+ { 0x0007, "\x07" },
+ { 0x0008, "\x08" },
+ { 0x000F, "\x0F" },
+ { 0x0010, "\x10" },
+ { 0x001F, "\x1F" },
+ { 0x0020, "\x20" },
+ { 0x003F, "\x3F" },
+ { 0x0040, "\x40" },
+ { 0x007F, "\x7F" },
+
+ { 0x0080, "\xC2\x80" },
+ { 0x0081, "\xC2\x81" },
+ { 0x0082, "\xC2\x82" },
+ { 0x0084, "\xC2\x84" },
+ { 0x0088, "\xC2\x88" },
+ { 0x0090, "\xC2\x90" },
+ { 0x00A0, "\xC2\xA0" },
+ { 0x00C0, "\xC3\x80" },
+ { 0x00FF, "\xC3\xBF" },
+ { 0x0100, "\xC4\x80" },
+ { 0x0101, "\xC4\x81" },
+ { 0x0102, "\xC4\x82" },
+ { 0x0104, "\xC4\x84" },
+ { 0x0108, "\xC4\x88" },
+ { 0x0110, "\xC4\x90" },
+ { 0x0120, "\xC4\xA0" },
+ { 0x0140, "\xC5\x80" },
+ { 0x0180, "\xC6\x80" },
+ { 0x01FF, "\xC7\xBF" },
+ { 0x0200, "\xC8\x80" },
+ { 0x0201, "\xC8\x81" },
+ { 0x0202, "\xC8\x82" },
+ { 0x0204, "\xC8\x84" },
+ { 0x0208, "\xC8\x88" },
+ { 0x0210, "\xC8\x90" },
+ { 0x0220, "\xC8\xA0" },
+ { 0x0240, "\xC9\x80" },
+ { 0x0280, "\xCA\x80" },
+ { 0x0300, "\xCC\x80" },
+ { 0x03FF, "\xCF\xBF" },
+ { 0x0400, "\xD0\x80" },
+ { 0x0401, "\xD0\x81" },
+ { 0x0402, "\xD0\x82" },
+ { 0x0404, "\xD0\x84" },
+ { 0x0408, "\xD0\x88" },
+ { 0x0410, "\xD0\x90" },
+ { 0x0420, "\xD0\xA0" },
+ { 0x0440, "\xD1\x80" },
+ { 0x0480, "\xD2\x80" },
+ { 0x0500, "\xD4\x80" },
+ { 0x0600, "\xD8\x80" },
+ { 0x07FF, "\xDF\xBF" },
+
+ { 0x0800, "\xE0\xA0\x80" },
+ { 0x0801, "\xE0\xA0\x81" },
+ { 0x0802, "\xE0\xA0\x82" },
+ { 0x0804, "\xE0\xA0\x84" },
+ { 0x0808, "\xE0\xA0\x88" },
+ { 0x0810, "\xE0\xA0\x90" },
+ { 0x0820, "\xE0\xA0\xA0" },
+ { 0x0840, "\xE0\xA1\x80" },
+ { 0x0880, "\xE0\xA2\x80" },
+ { 0x0900, "\xE0\xA4\x80" },
+ { 0x0A00, "\xE0\xA8\x80" },
+ { 0x0C00, "\xE0\xB0\x80" },
+ { 0x0FFF, "\xE0\xBF\xBF" },
+ { 0x1000, "\xE1\x80\x80" },
+ { 0x1001, "\xE1\x80\x81" },
+ { 0x1002, "\xE1\x80\x82" },
+ { 0x1004, "\xE1\x80\x84" },
+ { 0x1008, "\xE1\x80\x88" },
+ { 0x1010, "\xE1\x80\x90" },
+ { 0x1020, "\xE1\x80\xA0" },
+ { 0x1040, "\xE1\x81\x80" },
+ { 0x1080, "\xE1\x82\x80" },
+ { 0x1100, "\xE1\x84\x80" },
+ { 0x1200, "\xE1\x88\x80" },
+ { 0x1400, "\xE1\x90\x80" },
+ { 0x1800, "\xE1\xA0\x80" },
+ { 0x1FFF, "\xE1\xBF\xBF" },
+ { 0x2000, "\xE2\x80\x80" },
+ { 0x2001, "\xE2\x80\x81" },
+ { 0x2002, "\xE2\x80\x82" },
+ { 0x2004, "\xE2\x80\x84" },
+ { 0x2008, "\xE2\x80\x88" },
+ { 0x2010, "\xE2\x80\x90" },
+ { 0x2020, "\xE2\x80\xA0" },
+ { 0x2040, "\xE2\x81\x80" },
+ { 0x2080, "\xE2\x82\x80" },
+ { 0x2100, "\xE2\x84\x80" },
+ { 0x2200, "\xE2\x88\x80" },
+ { 0x2400, "\xE2\x90\x80" },
+ { 0x2800, "\xE2\xA0\x80" },
+ { 0x3000, "\xE3\x80\x80" },
+ { 0x3FFF, "\xE3\xBF\xBF" },
+ { 0x4000, "\xE4\x80\x80" },
+ { 0x4001, "\xE4\x80\x81" },
+ { 0x4002, "\xE4\x80\x82" },
+ { 0x4004, "\xE4\x80\x84" },
+ { 0x4008, "\xE4\x80\x88" },
+ { 0x4010, "\xE4\x80\x90" },
+ { 0x4020, "\xE4\x80\xA0" },
+ { 0x4040, "\xE4\x81\x80" },
+ { 0x4080, "\xE4\x82\x80" },
+ { 0x4100, "\xE4\x84\x80" },
+ { 0x4200, "\xE4\x88\x80" },
+ { 0x4400, "\xE4\x90\x80" },
+ { 0x4800, "\xE4\xA0\x80" },
+ { 0x5000, "\xE5\x80\x80" },
+ { 0x6000, "\xE6\x80\x80" },
+ { 0x7FFF, "\xE7\xBF\xBF" },
+ { 0x8000, "\xE8\x80\x80" },
+ { 0x8001, "\xE8\x80\x81" },
+ { 0x8002, "\xE8\x80\x82" },
+ { 0x8004, "\xE8\x80\x84" },
+ { 0x8008, "\xE8\x80\x88" },
+ { 0x8010, "\xE8\x80\x90" },
+ { 0x8020, "\xE8\x80\xA0" },
+ { 0x8040, "\xE8\x81\x80" },
+ { 0x8080, "\xE8\x82\x80" },
+ { 0x8100, "\xE8\x84\x80" },
+ { 0x8200, "\xE8\x88\x80" },
+ { 0x8400, "\xE8\x90\x80" },
+ { 0x8800, "\xE8\xA0\x80" },
+ { 0x9000, "\xE9\x80\x80" },
+ { 0xA000, "\xEA\x80\x80" },
+ { 0xC000, "\xEC\x80\x80" },
+ { 0xFFFF, "\xEF\xBF\xBF" }
+
+};
+
+/*
+ * UTF-16 vectors
+ */
+
+struct utf16 utf16[] = {
+ { 0x00010000, { 0xD800, 0xDC00 } },
+ { 0x00010001, { 0xD800, 0xDC01 } },
+ { 0x00010002, { 0xD800, 0xDC02 } },
+ { 0x00010003, { 0xD800, 0xDC03 } },
+ { 0x00010004, { 0xD800, 0xDC04 } },
+ { 0x00010007, { 0xD800, 0xDC07 } },
+ { 0x00010008, { 0xD800, 0xDC08 } },
+ { 0x0001000F, { 0xD800, 0xDC0F } },
+ { 0x00010010, { 0xD800, 0xDC10 } },
+ { 0x0001001F, { 0xD800, 0xDC1F } },
+ { 0x00010020, { 0xD800, 0xDC20 } },
+ { 0x0001003F, { 0xD800, 0xDC3F } },
+ { 0x00010040, { 0xD800, 0xDC40 } },
+ { 0x0001007F, { 0xD800, 0xDC7F } },
+ { 0x00010080, { 0xD800, 0xDC80 } },
+ { 0x00010081, { 0xD800, 0xDC81 } },
+ { 0x00010082, { 0xD800, 0xDC82 } },
+ { 0x00010084, { 0xD800, 0xDC84 } },
+ { 0x00010088, { 0xD800, 0xDC88 } },
+ { 0x00010090, { 0xD800, 0xDC90 } },
+ { 0x000100A0, { 0xD800, 0xDCA0 } },
+ { 0x000100C0, { 0xD800, 0xDCC0 } },
+ { 0x000100FF, { 0xD800, 0xDCFF } },
+ { 0x00010100, { 0xD800, 0xDD00 } },
+ { 0x00010101, { 0xD800, 0xDD01 } },
+ { 0x00010102, { 0xD800, 0xDD02 } },
+ { 0x00010104, { 0xD800, 0xDD04 } },
+ { 0x00010108, { 0xD800, 0xDD08 } },
+ { 0x00010110, { 0xD800, 0xDD10 } },
+ { 0x00010120, { 0xD800, 0xDD20 } },
+ { 0x00010140, { 0xD800, 0xDD40 } },
+ { 0x00010180, { 0xD800, 0xDD80 } },
+ { 0x000101FF, { 0xD800, 0xDDFF } },
+ { 0x00010200, { 0xD800, 0xDE00 } },
+ { 0x00010201, { 0xD800, 0xDE01 } },
+ { 0x00010202, { 0xD800, 0xDE02 } },
+ { 0x00010204, { 0xD800, 0xDE04 } },
+ { 0x00010208, { 0xD800, 0xDE08 } },
+ { 0x00010210, { 0xD800, 0xDE10 } },
+ { 0x00010220, { 0xD800, 0xDE20 } },
+ { 0x00010240, { 0xD800, 0xDE40 } },
+ { 0x00010280, { 0xD800, 0xDE80 } },
+ { 0x00010300, { 0xD800, 0xDF00 } },
+ { 0x000103FF, { 0xD800, 0xDFFF } },
+ { 0x00010400, { 0xD801, 0xDC00 } },
+ { 0x00010401, { 0xD801, 0xDC01 } },
+ { 0x00010402, { 0xD801, 0xDC02 } },
+ { 0x00010404, { 0xD801, 0xDC04 } },
+ { 0x00010408, { 0xD801, 0xDC08 } },
+ { 0x00010410, { 0xD801, 0xDC10 } },
+ { 0x00010420, { 0xD801, 0xDC20 } },
+ { 0x00010440, { 0xD801, 0xDC40 } },
+ { 0x00010480, { 0xD801, 0xDC80 } },
+ { 0x00010500, { 0xD801, 0xDD00 } },
+ { 0x00010600, { 0xD801, 0xDE00 } },
+ { 0x000107FF, { 0xD801, 0xDFFF } },
+ { 0x00010800, { 0xD802, 0xDC00 } },
+ { 0x00010801, { 0xD802, 0xDC01 } },
+ { 0x00010802, { 0xD802, 0xDC02 } },
+ { 0x00010804, { 0xD802, 0xDC04 } },
+ { 0x00010808, { 0xD802, 0xDC08 } },
+ { 0x00010810, { 0xD802, 0xDC10 } },
+ { 0x00010820, { 0xD802, 0xDC20 } },
+ { 0x00010840, { 0xD802, 0xDC40 } },
+ { 0x00010880, { 0xD802, 0xDC80 } },
+ { 0x00010900, { 0xD802, 0xDD00 } },
+ { 0x00010A00, { 0xD802, 0xDE00 } },
+ { 0x00010C00, { 0xD803, 0xDC00 } },
+ { 0x00010FFF, { 0xD803, 0xDFFF } },
+ { 0x00011000, { 0xD804, 0xDC00 } },
+ { 0x00011001, { 0xD804, 0xDC01 } },
+ { 0x00011002, { 0xD804, 0xDC02 } },
+ { 0x00011004, { 0xD804, 0xDC04 } },
+ { 0x00011008, { 0xD804, 0xDC08 } },
+ { 0x00011010, { 0xD804, 0xDC10 } },
+ { 0x00011020, { 0xD804, 0xDC20 } },
+ { 0x00011040, { 0xD804, 0xDC40 } },
+ { 0x00011080, { 0xD804, 0xDC80 } },
+ { 0x00011100, { 0xD804, 0xDD00 } },
+ { 0x00011200, { 0xD804, 0xDE00 } },
+ { 0x00011400, { 0xD805, 0xDC00 } },
+ { 0x00011800, { 0xD806, 0xDC00 } },
+ { 0x00011FFF, { 0xD807, 0xDFFF } },
+ { 0x00012000, { 0xD808, 0xDC00 } },
+ { 0x00012001, { 0xD808, 0xDC01 } },
+ { 0x00012002, { 0xD808, 0xDC02 } },
+ { 0x00012004, { 0xD808, 0xDC04 } },
+ { 0x00012008, { 0xD808, 0xDC08 } },
+ { 0x00012010, { 0xD808, 0xDC10 } },
+ { 0x00012020, { 0xD808, 0xDC20 } },
+ { 0x00012040, { 0xD808, 0xDC40 } },
+ { 0x00012080, { 0xD808, 0xDC80 } },
+ { 0x00012100, { 0xD808, 0xDD00 } },
+ { 0x00012200, { 0xD808, 0xDE00 } },
+ { 0x00012400, { 0xD809, 0xDC00 } },
+ { 0x00012800, { 0xD80A, 0xDC00 } },
+ { 0x00013000, { 0xD80C, 0xDC00 } },
+ { 0x00013FFF, { 0xD80F, 0xDFFF } },
+ { 0x00014000, { 0xD810, 0xDC00 } },
+ { 0x00014001, { 0xD810, 0xDC01 } },
+ { 0x00014002, { 0xD810, 0xDC02 } },
+ { 0x00014004, { 0xD810, 0xDC04 } },
+ { 0x00014008, { 0xD810, 0xDC08 } },
+ { 0x00014010, { 0xD810, 0xDC10 } },
+ { 0x00014020, { 0xD810, 0xDC20 } },
+ { 0x00014040, { 0xD810, 0xDC40 } },
+ { 0x00014080, { 0xD810, 0xDC80 } },
+ { 0x00014100, { 0xD810, 0xDD00 } },
+ { 0x00014200, { 0xD810, 0xDE00 } },
+ { 0x00014400, { 0xD811, 0xDC00 } },
+ { 0x00014800, { 0xD812, 0xDC00 } },
+ { 0x00015000, { 0xD814, 0xDC00 } },
+ { 0x00016000, { 0xD818, 0xDC00 } },
+ { 0x00017FFF, { 0xD81F, 0xDFFF } },
+ { 0x00018000, { 0xD820, 0xDC00 } },
+ { 0x00018001, { 0xD820, 0xDC01 } },
+ { 0x00018002, { 0xD820, 0xDC02 } },
+ { 0x00018004, { 0xD820, 0xDC04 } },
+ { 0x00018008, { 0xD820, 0xDC08 } },
+ { 0x00018010, { 0xD820, 0xDC10 } },
+ { 0x00018020, { 0xD820, 0xDC20 } },
+ { 0x00018040, { 0xD820, 0xDC40 } },
+ { 0x00018080, { 0xD820, 0xDC80 } },
+ { 0x00018100, { 0xD820, 0xDD00 } },
+ { 0x00018200, { 0xD820, 0xDE00 } },
+ { 0x00018400, { 0xD821, 0xDC00 } },
+ { 0x00018800, { 0xD822, 0xDC00 } },
+ { 0x00019000, { 0xD824, 0xDC00 } },
+ { 0x0001A000, { 0xD828, 0xDC00 } },
+ { 0x0001C000, { 0xD830, 0xDC00 } },
+ { 0x0001FFFF, { 0xD83F, 0xDFFF } },
+ { 0x00020000, { 0xD840, 0xDC00 } },
+ { 0x00020001, { 0xD840, 0xDC01 } },
+ { 0x00020002, { 0xD840, 0xDC02 } },
+ { 0x00020004, { 0xD840, 0xDC04 } },
+ { 0x00020008, { 0xD840, 0xDC08 } },
+ { 0x00020010, { 0xD840, 0xDC10 } },
+ { 0x00020020, { 0xD840, 0xDC20 } },
+ { 0x00020040, { 0xD840, 0xDC40 } },
+ { 0x00020080, { 0xD840, 0xDC80 } },
+ { 0x00020100, { 0xD840, 0xDD00 } },
+ { 0x00020200, { 0xD840, 0xDE00 } },
+ { 0x00020400, { 0xD841, 0xDC00 } },
+ { 0x00020800, { 0xD842, 0xDC00 } },
+ { 0x00021000, { 0xD844, 0xDC00 } },
+ { 0x00022000, { 0xD848, 0xDC00 } },
+ { 0x00024000, { 0xD850, 0xDC00 } },
+ { 0x00028000, { 0xD860, 0xDC00 } },
+ { 0x0002FFFF, { 0xD87F, 0xDFFF } },
+ { 0x00030000, { 0xD880, 0xDC00 } },
+ { 0x00030001, { 0xD880, 0xDC01 } },
+ { 0x00030002, { 0xD880, 0xDC02 } },
+ { 0x00030004, { 0xD880, 0xDC04 } },
+ { 0x00030008, { 0xD880, 0xDC08 } },
+ { 0x00030010, { 0xD880, 0xDC10 } },
+ { 0x00030020, { 0xD880, 0xDC20 } },
+ { 0x00030040, { 0xD880, 0xDC40 } },
+ { 0x00030080, { 0xD880, 0xDC80 } },
+ { 0x00030100, { 0xD880, 0xDD00 } },
+ { 0x00030200, { 0xD880, 0xDE00 } },
+ { 0x00030400, { 0xD881, 0xDC00 } },
+ { 0x00030800, { 0xD882, 0xDC00 } },
+ { 0x00031000, { 0xD884, 0xDC00 } },
+ { 0x00032000, { 0xD888, 0xDC00 } },
+ { 0x00034000, { 0xD890, 0xDC00 } },
+ { 0x00038000, { 0xD8A0, 0xDC00 } },
+ { 0x0003FFFF, { 0xD8BF, 0xDFFF } },
+ { 0x00040000, { 0xD8C0, 0xDC00 } },
+ { 0x00040001, { 0xD8C0, 0xDC01 } },
+ { 0x00040002, { 0xD8C0, 0xDC02 } },
+ { 0x00040004, { 0xD8C0, 0xDC04 } },
+ { 0x00040008, { 0xD8C0, 0xDC08 } },
+ { 0x00040010, { 0xD8C0, 0xDC10 } },
+ { 0x00040020, { 0xD8C0, 0xDC20 } },
+ { 0x00040040, { 0xD8C0, 0xDC40 } },
+ { 0x00040080, { 0xD8C0, 0xDC80 } },
+ { 0x00040100, { 0xD8C0, 0xDD00 } },
+ { 0x00040200, { 0xD8C0, 0xDE00 } },
+ { 0x00040400, { 0xD8C1, 0xDC00 } },
+ { 0x00040800, { 0xD8C2, 0xDC00 } },
+ { 0x00041000, { 0xD8C4, 0xDC00 } },
+ { 0x00042000, { 0xD8C8, 0xDC00 } },
+ { 0x00044000, { 0xD8D0, 0xDC00 } },
+ { 0x00048000, { 0xD8E0, 0xDC00 } },
+ { 0x0004FFFF, { 0xD8FF, 0xDFFF } },
+ { 0x00050000, { 0xD900, 0xDC00 } },
+ { 0x00050001, { 0xD900, 0xDC01 } },
+ { 0x00050002, { 0xD900, 0xDC02 } },
+ { 0x00050004, { 0xD900, 0xDC04 } },
+ { 0x00050008, { 0xD900, 0xDC08 } },
+ { 0x00050010, { 0xD900, 0xDC10 } },
+ { 0x00050020, { 0xD900, 0xDC20 } },
+ { 0x00050040, { 0xD900, 0xDC40 } },
+ { 0x00050080, { 0xD900, 0xDC80 } },
+ { 0x00050100, { 0xD900, 0xDD00 } },
+ { 0x00050200, { 0xD900, 0xDE00 } },
+ { 0x00050400, { 0xD901, 0xDC00 } },
+ { 0x00050800, { 0xD902, 0xDC00 } },
+ { 0x00051000, { 0xD904, 0xDC00 } },
+ { 0x00052000, { 0xD908, 0xDC00 } },
+ { 0x00054000, { 0xD910, 0xDC00 } },
+ { 0x00058000, { 0xD920, 0xDC00 } },
+ { 0x00060000, { 0xD940, 0xDC00 } },
+ { 0x00070000, { 0xD980, 0xDC00 } },
+ { 0x0007FFFF, { 0xD9BF, 0xDFFF } },
+ { 0x00080000, { 0xD9C0, 0xDC00 } },
+ { 0x00080001, { 0xD9C0, 0xDC01 } },
+ { 0x00080002, { 0xD9C0, 0xDC02 } },
+ { 0x00080004, { 0xD9C0, 0xDC04 } },
+ { 0x00080008, { 0xD9C0, 0xDC08 } },
+ { 0x00080010, { 0xD9C0, 0xDC10 } },
+ { 0x00080020, { 0xD9C0, 0xDC20 } },
+ { 0x00080040, { 0xD9C0, 0xDC40 } },
+ { 0x00080080, { 0xD9C0, 0xDC80 } },
+ { 0x00080100, { 0xD9C0, 0xDD00 } },
+ { 0x00080200, { 0xD9C0, 0xDE00 } },
+ { 0x00080400, { 0xD9C1, 0xDC00 } },
+ { 0x00080800, { 0xD9C2, 0xDC00 } },
+ { 0x00081000, { 0xD9C4, 0xDC00 } },
+ { 0x00082000, { 0xD9C8, 0xDC00 } },
+ { 0x00084000, { 0xD9D0, 0xDC00 } },
+ { 0x00088000, { 0xD9E0, 0xDC00 } },
+ { 0x0008FFFF, { 0xD9FF, 0xDFFF } },
+ { 0x00090000, { 0xDA00, 0xDC00 } },
+ { 0x00090001, { 0xDA00, 0xDC01 } },
+ { 0x00090002, { 0xDA00, 0xDC02 } },
+ { 0x00090004, { 0xDA00, 0xDC04 } },
+ { 0x00090008, { 0xDA00, 0xDC08 } },
+ { 0x00090010, { 0xDA00, 0xDC10 } },
+ { 0x00090020, { 0xDA00, 0xDC20 } },
+ { 0x00090040, { 0xDA00, 0xDC40 } },
+ { 0x00090080, { 0xDA00, 0xDC80 } },
+ { 0x00090100, { 0xDA00, 0xDD00 } },
+ { 0x00090200, { 0xDA00, 0xDE00 } },
+ { 0x00090400, { 0xDA01, 0xDC00 } },
+ { 0x00090800, { 0xDA02, 0xDC00 } },
+ { 0x00091000, { 0xDA04, 0xDC00 } },
+ { 0x00092000, { 0xDA08, 0xDC00 } },
+ { 0x00094000, { 0xDA10, 0xDC00 } },
+ { 0x00098000, { 0xDA20, 0xDC00 } },
+ { 0x000A0000, { 0xDA40, 0xDC00 } },
+ { 0x000B0000, { 0xDA80, 0xDC00 } },
+ { 0x000C0000, { 0xDAC0, 0xDC00 } },
+ { 0x000D0000, { 0xDB00, 0xDC00 } },
+ { 0x000FFFFF, { 0xDBBF, 0xDFFF } },
+ { 0x0010FFFF, { 0xDBFF, 0xDFFF } }
+
+};
+
+/* illegal utf8 sequences */
+char *utf8_bad[] = {
+ "\xC0\x80",
+ "\xC1\xBF",
+ "\xE0\x80\x80",
+ "\xE0\x9F\xBF",
+ "\xF0\x80\x80\x80",
+ "\xF0\x8F\xBF\xBF",
+ "\xF4\x90\x80\x80",
+ "\xF7\xBF\xBF\xBF",
+ "\xF8\x80\x80\x80\x80",
+ "\xF8\x88\x80\x80\x80",
+ "\xF8\x92\x80\x80\x80",
+ "\xF8\x9F\xBF\xBF\xBF",
+ "\xF8\xA0\x80\x80\x80",
+ "\xF8\xA8\x80\x80\x80",
+ "\xF8\xB0\x80\x80\x80",
+ "\xF8\xBF\xBF\xBF\xBF",
+ "\xF9\x80\x80\x80\x88",
+ "\xF9\x84\x80\x80\x80",
+ "\xF9\xBF\xBF\xBF\xBF",
+ "\xFA\x80\x80\x80\x80",
+ "\xFA\x90\x80\x80\x80",
+ "\xFB\xBF\xBF\xBF\xBF",
+ "\xFC\x84\x80\x80\x80\x81",
+ "\xFC\x85\x80\x80\x80\x80",
+ "\xFC\x86\x80\x80\x80\x80",
+ "\xFC\x87\xBF\xBF\xBF\xBF",
+ "\xFC\x88\xA0\x80\x80\x80",
+ "\xFC\x89\x80\x80\x80\x80",
+ "\xFC\x8A\x80\x80\x80\x80",
+ "\xFC\x90\x80\x80\x80\x82",
+ "\xFD\x80\x80\x80\x80\x80",
+ "\xFD\xBF\xBF\xBF\xBF\xBF",
+ "\x80",
+ "\xC3",
+ "\xC3\xC3\x80",
+ "\xED\xA0\x80",
+ "\xED\xBF\x80",
+ "\xED\xBF\xBF",
+ "\xED\xA0\x80\xE0\xBF\xBF",
+};
+
+static void
+dump_utf8
+(
+ char *word,
+ unsigned char *utf8,
+ char *end
+)
+{
+ fprintf(stdout, "%s ", word);
+ for( ; *utf8; utf8++ ) {
+ fprintf(stdout, "%02.2x ", (unsigned int)*utf8);
+ }
+ fprintf(stdout, "%s", end);
+}
+
+static PRBool
+test_ucs4_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ struct ucs4 *e = &ucs4[i];
+ PRBool result;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint32 back = 0;
+
+ (void)memset(utf8, 0, sizeof(utf8));
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8\n", e->c);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (len >= sizeof(utf8)) ||
+ (strlen(e->utf8) != len) ||
+ (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x%08.8x to UTF-8: ", e->c);
+ dump_utf8("expected", e->utf8, ", ");
+ dump_utf8("received", utf8, "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back, sizeof(back), &len);
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UCS-4\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back) != len) || (e->c != back) ) {
+ dump_utf8("Wrong conversion of UTF-8", utf8, " to UCS-4:");
+ fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back);
+ rv = PR_FALSE;
+ continue;
+ }
+ }
+
+ return rv;
+}
+
+static PRBool
+test_ucs2_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ struct ucs2 *e = &ucs2[i];
+ PRBool result;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint16 back = 0;
+
+ (void)memset(utf8, 0, sizeof(utf8));
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-2 0x%04.4x to UTF-8\n", e->c);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (len >= sizeof(utf8)) ||
+ (strlen(e->utf8) != len) ||
+ (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+ fprintf(stdout, "Wrong conversion of UCS-2 0x%04.4x to UTF-8: ", e->c);
+ dump_utf8("expected", e->utf8, ", ");
+ dump_utf8("received", utf8, "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back, sizeof(back), &len);
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UCS-2\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back) != len) || (e->c != back) ) {
+ dump_utf8("Wrong conversion of UTF-8", utf8, "to UCS-2:");
+ fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back);
+ rv = PR_FALSE;
+ continue;
+ }
+ }
+
+ return rv;
+}
+
+static PRBool
+test_utf16_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(utf16)/sizeof(utf16[0]); i++ ) {
+ struct utf16 *e = &utf16[i];
+ PRBool result;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint32 back32 = 0;
+ PRUint16 back[2];
+
+ (void)memset(utf8, 0, sizeof(utf8));
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->w[0], sizeof(e->w), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UTF-16 0x%04.4x 0x%04.4x to UTF-8\n",
+ e->w[0], e->w[1]);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back32, sizeof(back32), &len);
+
+ if( 4 != len ) {
+ fprintf(stdout, "Failed to convert UTF-16 0x%04.4x 0x%04.4x to UTF-8: "
+ "unexpected len %d\n", e->w[0], e->w[1], len);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ utf8[len] = '\0'; /* null-terminate for printing */
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UCS-4 (utf-16 test)\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back32) != len) || (e->c != back32) ) {
+ fprintf(stdout, "Wrong conversion of UTF-16 0x%04.4x 0x%04.4x ",
+ e->w[0], e->w[1]);
+ dump_utf8("to UTF-8", utf8, "and then to UCS-4: ");
+ if( sizeof(back32) != len ) {
+ fprintf(stdout, "len is %d\n", len);
+ } else {
+ fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back32);
+ }
+ rv = PR_FALSE;
+ continue;
+ }
+
+ (void)memset(utf8, 0, sizeof(utf8));
+ back[0] = back[1] = 0;
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8 (utf-16 test)\n",
+ e->c);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back[0], sizeof(back), &len);
+
+ if( 4 != len ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8: "
+ "unexpected len %d\n", e->c, len);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ utf8[len] = '\0'; /* null-terminate for printing */
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UTF-16\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back) != len) || (e->w[0] != back[0]) || (e->w[1] != back[1]) ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x%08.8x to UTF-8", e->c);
+ dump_utf8("", utf8, "and then to UTF-16:");
+ if( sizeof(back) != len ) {
+ fprintf(stdout, "len is %d\n", len);
+ } else {
+ fprintf(stdout, "expected 0x%04.4x 0x%04.4x, received 0x%04.4x 0x%04.4xx\n",
+ e->w[0], e->w[1], back[0], back[1]);
+ }
+ rv = PR_FALSE;
+ continue;
+ }
+ }
+
+ return rv;
+}
+
+static PRBool
+test_utf8_bad_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(utf8_bad)/sizeof(utf8_bad[0]); i++ ) {
+ PRBool result;
+ unsigned char destbuf[30];
+ unsigned int len = 0;
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ (unsigned char *)utf8_bad[i], strlen(utf8_bad[i]), destbuf, sizeof(destbuf), &len);
+
+ if( result ) {
+ dump_utf8("Failed to detect bad UTF-8 string converting to UCS2: ", utf8_bad[i], "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ (unsigned char *)utf8_bad[i], strlen(utf8_bad[i]), destbuf, sizeof(destbuf), &len);
+
+ if( result ) {
+ dump_utf8("Failed to detect bad UTF-8 string converting to UCS4: ", utf8_bad[i], "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ }
+
+ return rv;
+}
+
+static PRBool
+test_iso88591_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ struct ucs2 *e = &ucs2[i];
+ PRBool result;
+ unsigned char iso88591;
+ unsigned char utf8[3];
+ unsigned int len = 0;
+
+ if (ntohs(e->c) > 0xFF) continue;
+
+ (void)memset(utf8, 0, sizeof(utf8));
+ iso88591 = ntohs(e->c);
+
+ result = sec_port_iso88591_utf8_conversion_function(&iso88591,
+ 1, utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert ISO-8859-1 0x%02.2x to UTF-8\n", iso88591);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (len >= sizeof(utf8)) ||
+ (strlen(e->utf8) != len) ||
+ (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+ fprintf(stdout, "Wrong conversion of ISO-8859-1 0x%02.2x to UTF-8: ", iso88591);
+ dump_utf8("expected", e->utf8, ", ");
+ dump_utf8("received", utf8, "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ }
+
+ return rv;
+}
+
+static PRBool
+test_zeroes
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ PRBool result;
+ PRUint32 lzero = 0;
+ PRUint16 szero = 0;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint32 lback = 1;
+ PRUint16 sback = 1;
+
+ (void)memset(utf8, 1, sizeof(utf8));
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&lzero, sizeof(lzero), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x00000000 to UTF-8\n");
+ rv = PR_FALSE;
+ } else if( 1 != len ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x00000000: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( '\0' != *utf8 ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x00000000: expected 00 ,"
+ "received %02.2x\n", (unsigned int)*utf8);
+ rv = PR_FALSE;
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ "", 1, (unsigned char *)&lback, sizeof(lback), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UTF-8 00 to UCS-4\n");
+ rv = PR_FALSE;
+ } else if( 4 != len ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-4: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( 0 != lback ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-4: "
+ "expected 0x00000000, received 0x%08.8x\n", lback);
+ rv = PR_FALSE;
+ }
+
+ (void)memset(utf8, 1, sizeof(utf8));
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&szero, sizeof(szero), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-2 0x0000 to UTF-8\n");
+ rv = PR_FALSE;
+ } else if( 1 != len ) {
+ fprintf(stdout, "Wrong conversion of UCS-2 0x0000: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( '\0' != *utf8 ) {
+ fprintf(stdout, "Wrong conversion of UCS-2 0x0000: expected 00 ,"
+ "received %02.2x\n", (unsigned int)*utf8);
+ rv = PR_FALSE;
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ "", 1, (unsigned char *)&sback, sizeof(sback), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UTF-8 00 to UCS-2\n");
+ rv = PR_FALSE;
+ } else if( 2 != len ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-2: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( 0 != sback ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-2: "
+ "expected 0x0000, received 0x%04.4x\n", sback);
+ rv = PR_FALSE;
+ }
+
+ return rv;
+}
+
+static PRBool
+test_multichars
+(
+ void
+)
+{
+ int i;
+ unsigned int len, lenout;
+ PRUint32 *ucs4s;
+ char *ucs4_utf8;
+ PRUint16 *ucs2s;
+ char *ucs2_utf8;
+ void *tmp;
+ PRBool result;
+
+ ucs4s = (PRUint32 *)calloc(sizeof(ucs4)/sizeof(ucs4[0]), sizeof(PRUint32));
+ ucs2s = (PRUint16 *)calloc(sizeof(ucs2)/sizeof(ucs2[0]), sizeof(PRUint16));
+
+ if( ((PRUint32 *)NULL == ucs4s) || ((PRUint16 *)NULL == ucs2s) ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ len = 0;
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ ucs4s[i] = ucs4[i].c;
+ len += strlen(ucs4[i].utf8);
+ }
+
+ ucs4_utf8 = (char *)malloc(len);
+
+ len = 0;
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ ucs2s[i] = ucs2[i].c;
+ len += strlen(ucs2[i].utf8);
+ }
+
+ ucs2_utf8 = (char *)malloc(len);
+
+ if( ((char *)NULL == ucs4_utf8) || ((char *)NULL == ucs2_utf8) ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ *ucs4_utf8 = '\0';
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ strcat(ucs4_utf8, ucs4[i].utf8);
+ }
+
+ *ucs2_utf8 = '\0';
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ strcat(ucs2_utf8, ucs2[i].utf8);
+ }
+
+ /* UTF-8 -> UCS-4 */
+ len = sizeof(ucs4)/sizeof(ucs4[0]) * sizeof(PRUint32);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ ucs4_utf8, strlen(ucs4_utf8), tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UTF-8 to UCS-4\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UTF-8 to UCS-4\n");
+ goto loser;
+ }
+
+ if( 0 != memcmp(ucs4s, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UTF-8 to UCS-4\n");
+ goto loser;
+ }
+
+ free(tmp); tmp = (void *)NULL;
+
+ /* UCS-4 -> UTF-8 */
+ len = strlen(ucs4_utf8);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)ucs4s, sizeof(ucs4)/sizeof(ucs4[0]) * sizeof(PRUint32),
+ tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UCS-4 to UTF-8\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UCS-4 to UTF-8\n");
+ goto loser;
+ }
+
+ if( 0 != strncmp(ucs4_utf8, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UCS-4 to UTF-8\n");
+ goto loser;
+ }
+
+ free(tmp); tmp = (void *)NULL;
+
+ /* UTF-8 -> UCS-2 */
+ len = sizeof(ucs2)/sizeof(ucs2[0]) * sizeof(PRUint16);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ ucs2_utf8, strlen(ucs2_utf8), tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UTF-8 to UCS-2\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UTF-8 to UCS-2\n");
+ goto loser;
+ }
+
+ if( 0 != memcmp(ucs2s, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UTF-8 to UCS-2\n");
+ goto loser;
+ }
+
+ free(tmp); tmp = (void *)NULL;
+
+ /* UCS-2 -> UTF-8 */
+ len = strlen(ucs2_utf8);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)ucs2s, sizeof(ucs2)/sizeof(ucs2[0]) * sizeof(PRUint16),
+ tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UCS-2 to UTF-8\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UCS-2 to UTF-8\n");
+ goto loser;
+ }
+
+ if( 0 != strncmp(ucs2_utf8, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UCS-2 to UTF-8\n");
+ goto loser;
+ }
+
+ /* implement UTF16 */
+
+ result = PR_TRUE;
+ goto done;
+
+ loser:
+ result = PR_FALSE;
+ done:
+ free(ucs4s);
+ free(ucs4_utf8);
+ free(ucs2s);
+ free(ucs2_utf8);
+ if( (void *)NULL != tmp ) free(tmp);
+ return result;
+}
+
+void
+byte_order
+(
+ void
+)
+{
+ /*
+ * The implementation (now) expects the 16- and 32-bit characters
+ * to be in network byte order, not host byte order. Therefore I
+ * have to byteswap all those test vectors above. hton[ls] may be
+ * functions, so I have to do this dynamically. If you want to
+ * use this code to do host byte order conversions, just remove
+ * the call in main() to this function.
+ */
+
+ int i;
+
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ struct ucs4 *e = &ucs4[i];
+ e->c = htonl(e->c);
+ }
+
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ struct ucs2 *e = &ucs2[i];
+ e->c = htons(e->c);
+ }
+
+ for( i = 0; i < sizeof(utf16)/sizeof(utf16[0]); i++ ) {
+ struct utf16 *e = &utf16[i];
+ e->c = htonl(e->c);
+ e->w[0] = htons(e->w[0]);
+ e->w[1] = htons(e->w[1]);
+ }
+
+ return;
+}
+
+int
+main
+(
+ int argc,
+ char *argv[]
+)
+{
+ byte_order();
+
+ if( test_ucs4_chars() &&
+ test_ucs2_chars() &&
+ test_utf16_chars() &&
+ test_utf8_bad_chars() &&
+ test_iso88591_chars() &&
+ test_zeroes() &&
+ test_multichars() &&
+ PR_TRUE ) {
+ fprintf(stderr, "PASS\n");
+ return 1;
+ } else {
+ fprintf(stderr, "FAIL\n");
+ return 0;
+ }
+}
+
+#endif /* TEST_UTF8 */
diff --git a/lib/util/utilmod.c b/lib/util/utilmod.c
new file mode 100644
index 000000000..d051f7fe8
--- /dev/null
+++ b/lib/util/utilmod.c
@@ -0,0 +1,684 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * The following code handles the storage of PKCS 11 modules used by the
+ * NSS. For the rest of NSS, only one kind of database handle exists:
+ *
+ * SFTKDBHandle
+ *
+ * There is one SFTKDBHandle for each key database and one for each cert
+ * database. These databases are opened as associated pairs, one pair per
+ * slot. SFTKDBHandles are reference counted objects.
+ *
+ * Each SFTKDBHandle points to a low level database handle (SDB). This handle
+ * represents the underlying physical database. These objects are not
+ * reference counted, and are 'owned' by their respective SFTKDBHandles.
+ */
+
+#include "prprf.h"
+#include "prsystem.h"
+#include "secport.h"
+#include "utilpars.h"
+#include "secerr.h"
+#if defined (_WIN32)
+#include <io.h>
+#endif
+
+/****************************************************************
+ *
+ * Secmod database.
+ *
+ * The new secmod database is simply a text file with each of the module
+ * entries in the following form:
+ *
+ * #
+ * # This is a comment The next line is the library to load
+ * library=libmypkcs11.so
+ * name="My PKCS#11 module"
+ * params="my library's param string"
+ * nss="NSS parameters"
+ * other="parameters for other libraries and applications"
+ *
+ * library=libmynextpk11.so
+ * name="My other PKCS#11 module"
+ */
+
+
+/*
+ * Smart string cat functions. Automatically manage the memory.
+ * The first parameter is the source string. If it's null, we
+ * allocate memory for it. If it's not, we reallocate memory
+ * so the the concanenated string fits.
+ */
+static char *
+nssutil_DupnCat(char *baseString, const char *str, int str_len)
+{
+ int len = (baseString ? PORT_Strlen(baseString) : 0) + 1;
+ char *newString;
+
+ len += str_len;
+ newString = (char *) PORT_Realloc(baseString,len);
+ if (newString == NULL) {
+ PORT_Free(baseString);
+ return NULL;
+ }
+ if (baseString == NULL) *newString = 0;
+ return PORT_Strncat(newString,str, str_len);
+}
+
+/* Same as nssutil_DupnCat except it concatenates the full string, not a
+ * partial one */
+static char *
+nssutil_DupCat(char *baseString, const char *str)
+{
+ return nssutil_DupnCat(baseString, str, PORT_Strlen(str));
+}
+
+/* function to free up all the memory associated with a null terminated
+ * array of module specs */
+static SECStatus
+nssutil_releaseSpecList(char **moduleSpecList)
+{
+ if (moduleSpecList) {
+ char **index;
+ for(index = moduleSpecList; *index; index++) {
+ PORT_Free(*index);
+ }
+ PORT_Free(moduleSpecList);
+ }
+ return SECSuccess;
+}
+
+#define SECMOD_STEP 10
+static SECStatus
+nssutil_growList(char ***pModuleList, int *useCount, int last)
+{
+ char **newModuleList;
+
+ *useCount += SECMOD_STEP;
+ newModuleList = (char **)PORT_Realloc(*pModuleList,
+ *useCount*sizeof(char *));
+ if (newModuleList == NULL) {
+ return SECFailure;
+ }
+ PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP);
+ *pModuleList = newModuleList;
+ return SECSuccess;
+}
+
+static
+char *_NSSUTIL_GetOldSecmodName(const char *dbname,const char *filename)
+{
+ char *file = NULL;
+ char *dirPath = PORT_Strdup(dbname);
+ char *sep;
+
+ sep = PORT_Strrchr(dirPath,*NSSUTIL_PATH_SEPARATOR);
+#ifdef _WIN32
+ if (!sep) {
+ /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all
+ * platforms. */
+ sep = PORT_Strrchr(dirPath,'\\');
+ }
+#endif
+ if (sep) {
+ *sep = 0;
+ file = PR_smprintf("%s"NSSUTIL_PATH_SEPARATOR"%s", dirPath, filename);
+ } else {
+ file = PR_smprintf("%s", filename);
+ }
+ PORT_Free(dirPath);
+ return file;
+}
+
+static SECStatus nssutil_AddSecmodDB(const char *appName,
+ const char *filename, const char *dbname,
+ char *module, PRBool rw);
+
+#ifdef XP_UNIX
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+/* same as fopen, except it doesn't use umask, but explicit */
+FILE *
+lfopen(const char *name, const char *mode, int flags)
+{
+ int fd;
+ FILE *file;
+
+ fd = open(name, flags, 0600);
+ if (fd < 0) {
+ return NULL;
+ }
+ file = fdopen(fd, mode);
+ if (!file) {
+ close(fd);
+ }
+ /* file inherits fd */
+ return file;
+}
+
+#define MAX_LINE_LENGTH 2048
+
+/*
+ * Read all the existing modules in out of the file.
+ */
+static char **
+nssutil_ReadSecmodDB(const char *appName,
+ const char *filename, const char *dbname,
+ char *params, PRBool rw)
+{
+ FILE *fd = NULL;
+ char **moduleList = NULL;
+ int moduleCount = 1;
+ int useCount = SECMOD_STEP;
+ char line[MAX_LINE_LENGTH];
+ PRBool internal = PR_FALSE;
+ PRBool skipParams = PR_FALSE;
+ char *moduleString = NULL;
+ char *paramsValue=NULL;
+ PRBool failed = PR_TRUE;
+
+ moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **));
+ if (moduleList == NULL) return NULL;
+
+ if (dbname == NULL) {
+ goto return_default;
+ }
+
+ /* do we really want to use streams here */
+ fd = fopen(dbname, "r");
+ if (fd == NULL) goto done;
+
+ /*
+ * the following loop takes line separated config lines and collapses
+ * the lines to a single string, escaping and quoting as necessary.
+ */
+ /* loop state variables */
+ moduleString = NULL; /* current concatenated string */
+ internal = PR_FALSE; /* is this an internal module */
+ skipParams = PR_FALSE; /* did we find an override parameter block*/
+ paramsValue = NULL; /* the current parameter block value */
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ int len = PORT_Strlen(line);
+
+ /* remove the ending newline */
+ if (len && line[len-1] == '\n') {
+ len--;
+ line[len] = 0;
+ }
+ if (*line == '#') {
+ continue;
+ }
+ if (*line != 0) {
+ /*
+ * The PKCS #11 group standard assumes blocks of strings
+ * separated by new lines, clumped by new lines. Internally
+ * we take strings separated by spaces, so we may need to escape
+ * certain spaces.
+ */
+ char *value = PORT_Strchr(line,'=');
+
+ /* there is no value, write out the stanza as is */
+ if (value == NULL || value[1] == 0) {
+ if (moduleString) {
+ moduleString = nssutil_DupnCat(moduleString," ", 1);
+ if (moduleString == NULL) goto loser;
+ }
+ moduleString = nssutil_DupCat(moduleString, line);
+ if (moduleString == NULL) goto loser;
+ /* value is already quoted, just write it out */
+ } else if (value[1] == '"') {
+ if (moduleString) {
+ moduleString = nssutil_DupnCat(moduleString," ", 1);
+ if (moduleString == NULL) goto loser;
+ }
+ moduleString = nssutil_DupCat(moduleString, line);
+ if (moduleString == NULL) goto loser;
+ /* we have an override parameter section, remember that
+ * we found this (see following comment about why this
+ * is necessary). */
+ if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
+ skipParams = PR_TRUE;
+ }
+ /*
+ * The internal token always overrides it's parameter block
+ * from the passed in parameters, so wait until then end
+ * before we include the parameter block in case we need to
+ * override it. NOTE: if the parameter block is quoted with ("),
+ * this override does not happen. This allows you to override
+ * the application's parameter configuration.
+ *
+ * parameter block state is controlled by the following variables:
+ * skipParams - Bool : set to true of we have an override param
+ * block (all other blocks, either implicit or explicit are
+ * ignored).
+ * paramsValue - char * : pointer to the current param block. In
+ * the absence of overrides, paramsValue is set to the first
+ * parameter block we find. All subsequent blocks are ignored.
+ * When we find an internal token, the application passed
+ * parameters take precident.
+ */
+ } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
+ /* already have parameters */
+ if (paramsValue) {
+ continue;
+ }
+ paramsValue = NSSUTIL_Quote(&value[1], '"');
+ if (paramsValue == NULL) goto loser;
+ continue;
+ } else {
+ /* may need to quote */
+ char *newLine;
+ if (moduleString) {
+ moduleString = nssutil_DupnCat(moduleString," ", 1);
+ if (moduleString == NULL) goto loser;
+ }
+ moduleString = nssutil_DupnCat(moduleString,line,value-line+1);
+ if (moduleString == NULL) goto loser;
+ newLine = NSSUTIL_Quote(&value[1],'"');
+ if (newLine == NULL) goto loser;
+ moduleString = nssutil_DupCat(moduleString,newLine);
+ PORT_Free(newLine);
+ if (moduleString == NULL) goto loser;
+ }
+
+ /* check to see if it's internal? */
+ if (PORT_Strncasecmp(line, "NSS=", 4) == 0) {
+ /* This should be case insensitive! reviewers make
+ * me fix it if it's not */
+ if (PORT_Strstr(line,"internal")) {
+ internal = PR_TRUE;
+ /* override the parameters */
+ if (paramsValue) {
+ PORT_Free(paramsValue);
+ }
+ paramsValue = NSSUTIL_Quote(params, '"');
+ }
+ }
+ continue;
+ }
+ if ((moduleString == NULL) || (*moduleString == 0)) {
+ continue;
+ }
+
+ /*
+ * if we are here, we have found a complete stanza. Now write out
+ * any param section we may have found.
+ */
+ if (paramsValue) {
+ /* we had an override */
+ if (!skipParams) {
+ moduleString = nssutil_DupnCat(moduleString," parameters=", 12);
+ if (moduleString == NULL) goto loser;
+ moduleString = nssutil_DupCat(moduleString, paramsValue);
+ if (moduleString == NULL) goto loser;
+ }
+ PORT_Free(paramsValue);
+ paramsValue = NULL;
+ }
+
+ if ((moduleCount+1) >= useCount) {
+ SECStatus rv;
+ rv = nssutil_growList(&moduleList, &useCount, moduleCount+1);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
+ if (internal) {
+ moduleList[0] = moduleString;
+ } else {
+ moduleList[moduleCount] = moduleString;
+ moduleCount++;
+ }
+ moduleString = NULL;
+ internal = PR_FALSE;
+ skipParams = PR_FALSE;
+ }
+
+ if (moduleString) {
+ PORT_Free(moduleString);
+ moduleString = NULL;
+ }
+done:
+ /* if we couldn't open a pkcs11 database, look for the old one */
+ if (fd == NULL) {
+ char *olddbname = _NSSUTIL_GetOldSecmodName(dbname,filename);
+ PRStatus status;
+
+ /* couldn't get the old name */
+ if (!olddbname) {
+ goto bail;
+ }
+
+ /* old one exists */
+ status = PR_Access(olddbname, PR_ACCESS_EXISTS);
+ if (status == PR_SUCCESS) {
+ PR_smprintf_free(olddbname);
+ PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
+ return NULL;
+ }
+
+bail:
+ if (olddbname) {
+ PR_smprintf_free(olddbname);
+ }
+ }
+
+return_default:
+
+ if (!moduleList[0]) {
+ char * newParams;
+ moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1);
+ newParams = NSSUTIL_Quote(params,'"');
+ if (newParams == NULL) goto loser;
+ moduleString = nssutil_DupCat(moduleString, newParams);
+ PORT_Free(newParams);
+ if (moduleString == NULL) goto loser;
+ moduleString = nssutil_DupCat(moduleString,
+ NSSUTIL_DEFAULT_INTERNAL_INIT2);
+ if (moduleString == NULL) goto loser;
+ moduleString = nssutil_DupCat(moduleString,
+ NSSUTIL_DEFAULT_SFTKN_FLAGS);
+ if (moduleString == NULL) goto loser;
+ moduleString = nssutil_DupCat(moduleString,
+ NSSUTIL_DEFAULT_INTERNAL_INIT3);
+ if (moduleString == NULL) goto loser;
+ moduleList[0] = moduleString;
+ moduleString = NULL;
+ }
+ failed = PR_FALSE;
+
+loser:
+ /*
+ * cleanup
+ */
+ /* deal with trust cert db here */
+ if (moduleString) {
+ PORT_Free(moduleString);
+ moduleString = NULL;
+ }
+ if (paramsValue) {
+ PORT_Free(paramsValue);
+ paramsValue = NULL;
+ }
+ if (failed || (moduleList[0] == NULL)) {
+ /* This is wrong! FIXME */
+ nssutil_releaseSpecList(moduleList);
+ moduleList = NULL;
+ failed = PR_TRUE;
+ }
+ if (fd != NULL) {
+ fclose(fd);
+ } else if (!failed && rw) {
+ /* update our internal module */
+ nssutil_AddSecmodDB(appName,filename,dbname,moduleList[0],rw);
+ }
+ return moduleList;
+}
+
+static SECStatus
+nssutil_ReleaseSecmodDBData(const char *appName,
+ const char *filename, const char *dbname,
+ char **moduleSpecList, PRBool rw)
+{
+ if (moduleSpecList) {
+ nssutil_releaseSpecList(moduleSpecList);
+ }
+ return SECSuccess;
+}
+
+
+/*
+ * Delete a module from the Data Base
+ */
+static SECStatus
+nssutil_DeleteSecmodDB(const char *appName,
+ const char *filename, const char *dbname,
+ char *args, PRBool rw)
+{
+ /* SHDB_FIXME implement */
+ FILE *fd = NULL;
+ FILE *fd2 = NULL;
+ char line[MAX_LINE_LENGTH];
+ char *dbname2 = NULL;
+ char *block = NULL;
+ char *name = NULL;
+ char *lib = NULL;
+ int name_len, lib_len;
+ PRBool skip = PR_FALSE;
+ PRBool found = PR_FALSE;
+
+ if (dbname == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (!rw) {
+ PORT_SetError(SEC_ERROR_READ_ONLY);
+ return SECFailure;
+ }
+
+ dbname2 = PORT_Strdup(dbname);
+ if (dbname2 == NULL) goto loser;
+ dbname2[strlen(dbname)-1]++;
+
+ /* do we really want to use streams here */
+ fd = fopen(dbname, "r");
+ if (fd == NULL) goto loser;
+ fd2 = lfopen(dbname2, "w+", O_CREAT|O_RDWR|O_TRUNC);
+ if (fd2 == NULL) goto loser;
+
+ name = NSSUTIL_ArgGetParamValue("name",args);
+ if (name) {
+ name_len = PORT_Strlen(name);
+ }
+ lib = NSSUTIL_ArgGetParamValue("library",args);
+ if (lib) {
+ lib_len = PORT_Strlen(lib);
+ }
+
+
+ /*
+ * the following loop takes line separated config files and collapses
+ * the lines to a single string, escaping and quoting as necessary.
+ */
+ /* loop state variables */
+ block = NULL;
+ skip = PR_FALSE;
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ /* If we are processing a block (we haven't hit a blank line yet */
+ if (*line != '\n') {
+ /* skip means we are in the middle of a block we are deleting */
+ if (skip) {
+ continue;
+ }
+ /* if we haven't found the block yet, check to see if this block
+ * matches our requirements */
+ if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) &&
+ (PORT_Strncmp(line+5,name,name_len) == 0)) ||
+ (lib && (PORT_Strncasecmp(line,"library=",8) == 0) &&
+ (PORT_Strncmp(line+8,lib,lib_len) == 0)))) {
+
+ /* yup, we don't need to save any more data, */
+ PORT_Free(block);
+ block=NULL;
+ /* we don't need to collect more of this block */
+ skip = PR_TRUE;
+ /* we don't need to continue searching for the block */
+ found =PR_TRUE;
+ continue;
+ }
+ /* not our match, continue to collect data in this block */
+ block = nssutil_DupCat(block,line);
+ continue;
+ }
+ /* we've collected a block of data that wasn't the module we were
+ * looking for, write it out */
+ if (block) {
+ fwrite(block, PORT_Strlen(block), 1, fd2);
+ PORT_Free(block);
+ block = NULL;
+ }
+ /* If we didn't just delete the this block, keep the blank line */
+ if (!skip) {
+ fputs(line,fd2);
+ }
+ /* we are definately not in a deleted block anymore */
+ skip = PR_FALSE;
+ }
+ fclose(fd);
+ fclose(fd2);
+ if (found) {
+ /* rename dbname2 to dbname */
+ PR_Delete(dbname);
+ PR_Rename(dbname2,dbname);
+ } else {
+ PR_Delete(dbname2);
+ }
+ PORT_Free(dbname2);
+ PORT_Free(lib);
+ PORT_Free(name);
+ PORT_Free(block);
+ return SECSuccess;
+
+loser:
+ if (fd != NULL) {
+ fclose(fd);
+ }
+ if (fd2 != NULL) {
+ fclose(fd2);
+ }
+ if (dbname2) {
+ PR_Delete(dbname2);
+ PORT_Free(dbname2);
+ }
+ PORT_Free(lib);
+ PORT_Free(name);
+ return SECFailure;
+}
+
+/*
+ * Add a module to the Data base
+ */
+static SECStatus
+nssutil_AddSecmodDB(const char *appName,
+ const char *filename, const char *dbname,
+ char *module, PRBool rw)
+{
+ FILE *fd = NULL;
+ char *block = NULL;
+ PRBool libFound = PR_FALSE;
+
+ if (dbname == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* can't write to a read only module */
+ if (!rw) {
+ PORT_SetError(SEC_ERROR_READ_ONLY);
+ return SECFailure;
+ }
+
+ /* remove the previous version if it exists */
+ (void) nssutil_DeleteSecmodDB(appName, filename,
+ dbname, module, rw);
+
+ fd = lfopen(dbname, "a+", O_CREAT|O_RDWR|O_APPEND);
+ if (fd == NULL) {
+ return SECFailure;
+ }
+ module = NSSUTIL_ArgStrip(module);
+ while (*module) {
+ int count;
+ char *keyEnd = PORT_Strchr(module,'=');
+ char *value;
+
+ if (PORT_Strncmp(module, "library=", 8) == 0) {
+ libFound=PR_TRUE;
+ }
+ if (keyEnd == NULL) {
+ block = nssutil_DupCat(block, module);
+ break;
+ }
+ block = nssutil_DupnCat(block, module, keyEnd-module+1);
+ if (block == NULL) { goto loser; }
+ value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count);
+ if (value) {
+ block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value));
+ PORT_Free(value);
+ }
+ if (block == NULL) { goto loser; }
+ block = nssutil_DupnCat(block, "\n", 1);
+ module = keyEnd + 1 + count;
+ module = NSSUTIL_ArgStrip(module);
+ }
+ if (block) {
+ if (!libFound) {
+ fprintf(fd,"library=\n");
+ }
+ fwrite(block, PORT_Strlen(block), 1, fd);
+ fprintf(fd,"\n");
+ PORT_Free(block);
+ block = NULL;
+ }
+ fclose(fd);
+ return SECSuccess;
+
+loser:
+ PORT_Free(block);
+ fclose(fd);
+ return SECFailure;
+}
+
+
+char **
+NSSUTIL_DoModuleDBFunction(unsigned long function,char *parameters, void *args)
+{
+ char *secmod = NULL;
+ char *appName = NULL;
+ char *filename = NULL;
+ NSSDBType dbType = NSS_DB_TYPE_NONE;
+ PRBool rw;
+ static char *success="Success";
+ char **rvstr = NULL;
+
+
+ secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
+ &filename, &rw);
+ if ((dbType == NSS_DB_TYPE_LEGACY) ||
+ (dbType == NSS_DB_TYPE_MULTIACCESS)) {
+ /* we can't handle the old database, only softoken can */
+ PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
+ rvstr = NULL;
+ goto done;
+ }
+
+ switch (function) {
+ case SECMOD_MODULE_DB_FUNCTION_FIND:
+ rvstr = nssutil_ReadSecmodDB(appName,filename,
+ secmod,(char *)parameters,rw);
+ break;
+ case SECMOD_MODULE_DB_FUNCTION_ADD:
+ rvstr = (nssutil_AddSecmodDB(appName,filename,
+ secmod,(char *)args,rw) == SECSuccess) ? &success: NULL;
+ break;
+ case SECMOD_MODULE_DB_FUNCTION_DEL:
+ rvstr = (nssutil_DeleteSecmodDB(appName,filename,
+ secmod,(char *)args,rw) == SECSuccess) ? &success: NULL;
+ break;
+ case SECMOD_MODULE_DB_FUNCTION_RELEASE:
+ rvstr = (nssutil_ReleaseSecmodDBData(appName,filename,
+ secmod, (char **)args,rw) == SECSuccess) ? &success: NULL;
+ break;
+ }
+done:
+ if (secmod) PR_smprintf_free(secmod);
+ if (appName) PORT_Free(appName);
+ if (filename) PORT_Free(filename);
+ return rvstr;
+}
diff --git a/lib/util/utilmodt.h b/lib/util/utilmodt.h
new file mode 100644
index 000000000..825e59f8f
--- /dev/null
+++ b/lib/util/utilmodt.h
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UTILMODT_H_
+#define _UTILMODT_H_ 1
+
+/*
+ * these are SECMOD flags that would normally be in secmodt.h, but are needed
+ * for the parser in util. Fort this reason we preserve the SECMOD names.
+ */
+#define SECMOD_RSA_FLAG 0x00000001L
+#define SECMOD_DSA_FLAG 0x00000002L
+#define SECMOD_RC2_FLAG 0x00000004L
+#define SECMOD_RC4_FLAG 0x00000008L
+#define SECMOD_DES_FLAG 0x00000010L
+#define SECMOD_DH_FLAG 0x00000020L
+#define SECMOD_FORTEZZA_FLAG 0x00000040L
+#define SECMOD_RC5_FLAG 0x00000080L
+#define SECMOD_SHA1_FLAG 0x00000100L
+#define SECMOD_MD5_FLAG 0x00000200L
+#define SECMOD_MD2_FLAG 0x00000400L
+#define SECMOD_SSL_FLAG 0x00000800L
+#define SECMOD_TLS_FLAG 0x00001000L
+#define SECMOD_AES_FLAG 0x00002000L
+#define SECMOD_SHA256_FLAG 0x00004000L
+#define SECMOD_SHA512_FLAG 0x00008000L /* also for SHA384 */
+#define SECMOD_CAMELLIA_FLAG 0x00010000L /* = PUBLIC_MECH_CAMELLIA_FLAG */
+#define SECMOD_SEED_FLAG 0x00020000L
+/* reserved bit for future, do not use */
+#define SECMOD_RESERVED_FLAG 0X08000000L
+#define SECMOD_FRIENDLY_FLAG 0x10000000L
+#define SECMOD_RANDOM_FLAG 0x80000000L
+
+#define PK11_OWN_PW_DEFAULTS 0x20000000L
+#define PK11_DISABLE_FLAG 0x40000000L
+
+/* need to make SECMOD and PK11 prefixes consistent. */
+#define SECMOD_OWN_PW_DEFAULTS PK11_OWN_PW_DEFAULTS
+#define SECMOD_DISABLE_FLAG PK11_DISABLE_FLAG
+
+#endif /* _UTILMODT_H_ */
diff --git a/lib/util/utilpars.c b/lib/util/utilpars.c
new file mode 100644
index 000000000..4bb2d3ff9
--- /dev/null
+++ b/lib/util/utilpars.c
@@ -0,0 +1,1117 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * The following code handles the storage of PKCS 11 modules used by the
+ * NSS. This file is written to abstract away how the modules are
+ * stored so we can decide that later.
+ */
+#include "secport.h"
+#include "prprf.h"
+#include "prenv.h"
+#include "utilpars.h"
+#include "utilmodt.h"
+
+/*
+ * return the expected matching quote value for the one specified
+ */
+PRBool NSSUTIL_ArgGetPair(char c) {
+ switch (c) {
+ case '\'': return c;
+ case '\"': return c;
+ case '<': return '>';
+ case '{': return '}';
+ case '[': return ']';
+ case '(': return ')';
+ default: break;
+ }
+ return ' ';
+}
+
+PRBool NSSUTIL_ArgIsBlank(char c) {
+ return isspace((unsigned char )c);
+}
+
+PRBool NSSUTIL_ArgIsEscape(char c) {
+ return c == '\\';
+}
+
+PRBool NSSUTIL_ArgIsQuote(char c) {
+ switch (c) {
+ case '\'':
+ case '\"':
+ case '<':
+ case '{': /* } end curly to keep vi bracket matching working */
+ case '(': /* ) */
+ case '[': /* ] */ return PR_TRUE;
+ default: break;
+ }
+ return PR_FALSE;
+}
+
+char *NSSUTIL_ArgStrip(char *c) {
+ while (*c && NSSUTIL_ArgIsBlank(*c)) c++;
+ return c;
+}
+
+/*
+ * find the end of the current tag/value pair. string should be pointing just
+ * after the equal sign. Handles quoted characters.
+ */
+char *
+NSSUTIL_ArgFindEnd(char *string) {
+ char endChar = ' ';
+ PRBool lastEscape = PR_FALSE;
+
+ if (NSSUTIL_ArgIsQuote(*string)) {
+ endChar = NSSUTIL_ArgGetPair(*string);
+ string++;
+ }
+
+ for (;*string; string++) {
+ if (lastEscape) {
+ lastEscape = PR_FALSE;
+ continue;
+ }
+ if (NSSUTIL_ArgIsEscape(*string) && !lastEscape) {
+ lastEscape = PR_TRUE;
+ continue;
+ }
+ if ((endChar == ' ') && NSSUTIL_ArgIsBlank(*string)) break;
+ if (*string == endChar) {
+ break;
+ }
+ }
+
+ return string;
+}
+
+/*
+ * get the value pointed to by string. string should be pointing just beyond
+ * the equal sign.
+ */
+char *
+NSSUTIL_ArgFetchValue(char *string, int *pcount)
+{
+ char *end = NSSUTIL_ArgFindEnd(string);
+ char *retString, *copyString;
+ PRBool lastEscape = PR_FALSE;
+ int len;
+
+ len = end - string;
+ if (len == 0) {
+ *pcount = 0;
+ return NULL;
+ }
+
+ copyString = retString = (char *)PORT_Alloc(len+1);
+
+ if (*end) len++;
+ *pcount = len;
+ if (retString == NULL) return NULL;
+
+
+ if (NSSUTIL_ArgIsQuote(*string)) string++;
+ for (; string < end; string++) {
+ if (NSSUTIL_ArgIsEscape(*string) && !lastEscape) {
+ lastEscape = PR_TRUE;
+ continue;
+ }
+ lastEscape = PR_FALSE;
+ *copyString++ = *string;
+ }
+ *copyString = 0;
+ return retString;
+}
+
+/*
+ * point to the next parameter in string
+ */
+char *
+NSSUTIL_ArgSkipParameter(char *string)
+{
+ char *end;
+ /* look for the end of the <name>= */
+ for (;*string; string++) {
+ if (*string == '=') { string++; break; }
+ if (NSSUTIL_ArgIsBlank(*string)) return(string);
+ }
+
+ end = NSSUTIL_ArgFindEnd(string);
+ if (*end) end++;
+ return end;
+}
+
+/*
+ * get the value from that tag value pair.
+ */
+char *
+NSSUTIL_ArgGetParamValue(char *paramName,char *parameters)
+{
+ char searchValue[256];
+ int paramLen = strlen(paramName);
+ char *returnValue = NULL;
+ int next;
+
+ if ((parameters == NULL) || (*parameters == 0)) return NULL;
+
+ PORT_Assert(paramLen+2 < sizeof(searchValue));
+
+ PORT_Strcpy(searchValue,paramName);
+ PORT_Strcat(searchValue,"=");
+ while (*parameters) {
+ if (PORT_Strncasecmp(parameters,searchValue,paramLen+1) == 0) {
+ parameters += paramLen+1;
+ returnValue = NSSUTIL_ArgFetchValue(parameters,&next);
+ break;
+ } else {
+ parameters = NSSUTIL_ArgSkipParameter(parameters);
+ }
+ parameters = NSSUTIL_ArgStrip(parameters);
+ }
+ return returnValue;
+}
+
+/*
+ * find the next flag in the parameter list
+ */
+char *
+NSSUTIL_ArgNextFlag(char *flags)
+{
+ for (; *flags ; flags++) {
+ if (*flags == ',') {
+ flags++;
+ break;
+ }
+ }
+ return flags;
+}
+
+/*
+ * return true if the flag is set in the label parameter.
+ */
+PRBool
+NSSUTIL_ArgHasFlag(char *label, char *flag, char *parameters)
+{
+ char *flags,*index;
+ int len = strlen(flag);
+ PRBool found = PR_FALSE;
+
+ flags = NSSUTIL_ArgGetParamValue(label,parameters);
+ if (flags == NULL) return PR_FALSE;
+
+ for (index=flags; *index; index=NSSUTIL_ArgNextFlag(index)) {
+ if (PORT_Strncasecmp(index,flag,len) == 0) {
+ found=PR_TRUE;
+ break;
+ }
+ }
+ PORT_Free(flags);
+ return found;
+}
+
+/*
+ * decode a number. handle octal (leading '0'), hex (leading '0x') or decimal
+ */
+long
+NSSUTIL_ArgDecodeNumber(char *num)
+{
+ int radix = 10;
+ unsigned long value = 0;
+ long retValue = 0;
+ int sign = 1;
+ int digit;
+
+ if (num == NULL) return retValue;
+
+ num = NSSUTIL_ArgStrip(num);
+
+ if (*num == '-') {
+ sign = -1;
+ num++;
+ }
+
+ if (*num == '0') {
+ radix = 8;
+ num++;
+ if ((*num == 'x') || (*num == 'X')) {
+ radix = 16;
+ num++;
+ }
+ }
+
+
+ for ( ;*num; num++ ) {
+ if (isdigit(*num)) {
+ digit = *num - '0';
+ } else if ((*num >= 'a') && (*num <= 'f')) {
+ digit = *num - 'a' + 10;
+ } else if ((*num >= 'A') && (*num <= 'F')) {
+ digit = *num - 'A' + 10;
+ } else {
+ break;
+ }
+ if (digit >= radix) break;
+ value = value*radix + digit;
+ }
+
+ retValue = ((int) value) * sign;
+ return retValue;
+}
+
+/*
+ * parameters are tag value pairs. This function returns the tag or label (the
+ * value before the equal size.
+ */
+char *
+NSSUTIL_ArgGetLabel(char *inString, int *next)
+{
+ char *name=NULL;
+ char *string;
+ int len;
+
+ /* look for the end of the <label>= */
+ for (string = inString;*string; string++) {
+ if (*string == '=') { break; }
+ if (NSSUTIL_ArgIsBlank(*string)) break;
+ }
+
+ len = string - inString;
+
+ *next = len;
+ if (*string == '=') (*next) += 1;
+ if (len > 0) {
+ name = PORT_Alloc(len+1);
+ PORT_Strncpy(name,inString,len);
+ name[len] = 0;
+ }
+ return name;
+}
+
+/*
+ * read an argument at a Long integer
+ */
+long
+NSSUTIL_ArgReadLong(char *label,char *params, long defValue, PRBool *isdefault)
+{
+ char *value;
+ long retValue;
+ if (isdefault) *isdefault = PR_FALSE;
+
+ value = NSSUTIL_ArgGetParamValue(label,params);
+ if (value == NULL) {
+ if (isdefault) *isdefault = PR_TRUE;
+ return defValue;
+ }
+ retValue = NSSUTIL_ArgDecodeNumber(value);
+ if (value) PORT_Free(value);
+
+ return retValue;
+}
+
+
+/*
+ * prepare a string to be quoted with 'quote' marks. We do that by adding
+ * appropriate escapes.
+ */
+static int
+nssutil_escapeQuotesSize(const char *string, char quote, PRBool addquotes)
+{
+ int escapes = 0, size = 0;
+ const char *src;
+
+ size= addquotes ? 2 : 0;
+ for (src=string; *src ; src++) {
+ if ((*src == quote) || (*src == '\\')) escapes++;
+ size++;
+ }
+ return size+escapes+1;
+
+}
+
+static char *
+nssutil_escapeQuotes(const char *string, char quote, PRBool addquotes)
+{
+ char *newString = 0;
+ int size = 0;
+ const char *src;
+ char *dest;
+
+ size = nssutil_escapeQuotesSize(string, quote, addquotes);
+
+ dest = newString = PORT_ZAlloc(size);
+ if (newString == NULL) {
+ return NULL;
+ }
+
+ if (addquotes) *dest++=quote;
+ for (src=string; *src; src++,dest++) {
+ if ((*src == '\\') || (*src == quote)) {
+ *dest++ = '\\';
+ }
+ *dest = *src;
+ }
+ if (addquotes) *dest=quote;
+
+ return newString;
+}
+
+int
+NSSUTIL_EscapeSize(const char *string, char quote)
+{
+ return nssutil_escapeQuotesSize(string, quote, PR_FALSE);
+}
+
+char *
+NSSUTIL_Escape(const char *string, char quote)
+{
+ return nssutil_escapeQuotes(string, quote, PR_FALSE);
+}
+
+
+int
+NSSUTIL_QuoteSize(const char *string, char quote)
+{
+ return nssutil_escapeQuotesSize(string, quote, PR_TRUE);
+}
+
+char *
+NSSUTIL_Quote(const char *string, char quote)
+{
+ return nssutil_escapeQuotes(string, quote, PR_TRUE);
+}
+
+int
+NSSUTIL_DoubleEscapeSize(const char *string, char quote1, char quote2)
+{
+ int escapes = 0, size = 0;
+ const char *src;
+ for (src=string; *src ; src++) {
+ if (*src == '\\') escapes+=3; /* \\\\ */
+ if (*src == quote1) escapes+=2; /* \\quote1 */
+ if (*src == quote2) escapes++; /* \quote2 */
+ size++;
+ }
+
+ return escapes+size+1;
+}
+
+char *
+NSSUTIL_DoubleEscape(const char *string, char quote1, char quote2)
+{
+ char *round1 = NULL;
+ char *retValue = NULL;
+ if (string == NULL) {
+ goto done;
+ }
+ round1 = nssutil_escapeQuotes(string, quote1, PR_FALSE);
+ if (round1) {
+ retValue = nssutil_escapeQuotes(round1, quote2, PR_FALSE);
+ PORT_Free(round1);
+ }
+
+done:
+ if (retValue == NULL) {
+ retValue = PORT_Strdup("");
+ }
+ return retValue;
+}
+
+
+/************************************************************************
+ * These functions are used in contructing strings.
+ * NOTE: they will always return a string, but sometimes it will return
+ * a specific NULL string. These strings must be freed with util_freePair.
+ */
+
+/* string to return on error... */
+static char *nssutil_nullString = "";
+
+static char *
+nssutil_formatValue(PRArenaPool *arena, char *value, char quote)
+{
+ char *vp,*vp2,*retval;
+ int size = 0, escapes = 0;
+
+ for (vp=value; *vp ;vp++) {
+ if ((*vp == quote) || (*vp == NSSUTIL_ARG_ESCAPE)) escapes++;
+ size++;
+ }
+ if (arena) {
+ retval = PORT_ArenaZAlloc(arena,size+escapes+1);
+ } else {
+ retval = PORT_ZAlloc(size+escapes+1);
+ }
+ if (retval == NULL) return NULL;
+ vp2 = retval;
+ for (vp=value; *vp; vp++) {
+ if ((*vp == quote) || (*vp == NSSUTIL_ARG_ESCAPE))
+ *vp2++ = NSSUTIL_ARG_ESCAPE;
+ *vp2++ = *vp;
+ }
+ return retval;
+}
+
+
+static PRBool nssutil_argHasChar(char *v, char c)
+{
+ for ( ;*v; v++) {
+ if (*v == c) return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+static PRBool nssutil_argHasBlanks(char *v)
+{
+ for ( ;*v; v++) {
+ if (NSSUTIL_ArgIsBlank(*v)) return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+static char *
+nssutil_formatPair(char *name, char *value, char quote)
+{
+ char openQuote = quote;
+ char closeQuote = NSSUTIL_ArgGetPair(quote);
+ char *newValue = NULL;
+ char *returnValue;
+ PRBool need_quote = PR_FALSE;
+
+ if (!value || (*value == 0)) return nssutil_nullString;
+
+ if (nssutil_argHasBlanks(value) || NSSUTIL_ArgIsQuote(value[0]))
+ need_quote=PR_TRUE;
+
+ if ((need_quote && nssutil_argHasChar(value,closeQuote))
+ || nssutil_argHasChar(value,NSSUTIL_ARG_ESCAPE)) {
+ value = newValue = nssutil_formatValue(NULL, value,quote);
+ if (newValue == NULL) return nssutil_nullString;
+ }
+ if (need_quote) {
+ returnValue = PR_smprintf("%s=%c%s%c",name,openQuote,value,closeQuote);
+ } else {
+ returnValue = PR_smprintf("%s=%s",name,value);
+ }
+ if (returnValue == NULL) returnValue = nssutil_nullString;
+
+ if (newValue) PORT_Free(newValue);
+
+ return returnValue;
+}
+
+static char *nssutil_formatIntPair(char *name, unsigned long value,
+ unsigned long def)
+{
+ char *returnValue;
+
+ if (value == def) return nssutil_nullString;
+
+ returnValue = PR_smprintf("%s=%d",name,value);
+
+ return returnValue;
+}
+
+static void
+nssutil_freePair(char *pair)
+{
+ if (pair && pair != nssutil_nullString) {
+ PR_smprintf_free(pair);
+ }
+}
+
+
+/************************************************************************
+ * Parse the Slot specific parameters in the NSS params.
+ */
+
+struct nssutilArgSlotFlagTable {
+ char *name;
+ int len;
+ unsigned long value;
+};
+
+#define NSSUTIL_ARG_ENTRY(arg,flag) \
+{ #arg , sizeof(#arg)-1, flag }
+static struct nssutilArgSlotFlagTable nssutil_argSlotFlagTable[] = {
+ NSSUTIL_ARG_ENTRY(RSA,SECMOD_RSA_FLAG),
+ NSSUTIL_ARG_ENTRY(DSA,SECMOD_RSA_FLAG),
+ NSSUTIL_ARG_ENTRY(RC2,SECMOD_RC4_FLAG),
+ NSSUTIL_ARG_ENTRY(RC4,SECMOD_RC2_FLAG),
+ NSSUTIL_ARG_ENTRY(DES,SECMOD_DES_FLAG),
+ NSSUTIL_ARG_ENTRY(DH,SECMOD_DH_FLAG),
+ NSSUTIL_ARG_ENTRY(FORTEZZA,SECMOD_FORTEZZA_FLAG),
+ NSSUTIL_ARG_ENTRY(RC5,SECMOD_RC5_FLAG),
+ NSSUTIL_ARG_ENTRY(SHA1,SECMOD_SHA1_FLAG),
+ NSSUTIL_ARG_ENTRY(SHA256,SECMOD_SHA256_FLAG),
+ NSSUTIL_ARG_ENTRY(SHA512,SECMOD_SHA512_FLAG),
+ NSSUTIL_ARG_ENTRY(MD5,SECMOD_MD5_FLAG),
+ NSSUTIL_ARG_ENTRY(MD2,SECMOD_MD2_FLAG),
+ NSSUTIL_ARG_ENTRY(SSL,SECMOD_SSL_FLAG),
+ NSSUTIL_ARG_ENTRY(TLS,SECMOD_TLS_FLAG),
+ NSSUTIL_ARG_ENTRY(AES,SECMOD_AES_FLAG),
+ NSSUTIL_ARG_ENTRY(Camellia,SECMOD_CAMELLIA_FLAG),
+ NSSUTIL_ARG_ENTRY(SEED,SECMOD_SEED_FLAG),
+ NSSUTIL_ARG_ENTRY(PublicCerts,SECMOD_FRIENDLY_FLAG),
+ NSSUTIL_ARG_ENTRY(RANDOM,SECMOD_RANDOM_FLAG),
+ NSSUTIL_ARG_ENTRY(Disable, SECMOD_DISABLE_FLAG),
+};
+
+static int nssutil_argSlotFlagTableSize =
+ sizeof(nssutil_argSlotFlagTable)/sizeof(nssutil_argSlotFlagTable[0]);
+
+
+/* turn the slot flags into a bit mask */
+unsigned long
+NSSUTIL_ArgParseSlotFlags(char *label,char *params)
+{
+ char *flags,*index;
+ unsigned long retValue = 0;
+ int i;
+ PRBool all = PR_FALSE;
+
+ flags = NSSUTIL_ArgGetParamValue(label,params);
+ if (flags == NULL) return 0;
+
+ if (PORT_Strcasecmp(flags,"all") == 0) all = PR_TRUE;
+
+ for (index=flags; *index; index=NSSUTIL_ArgNextFlag(index)) {
+ for (i=0; i < nssutil_argSlotFlagTableSize; i++) {
+ if (all ||
+ (PORT_Strncasecmp(index, nssutil_argSlotFlagTable[i].name,
+ nssutil_argSlotFlagTable[i].len) == 0)) {
+ retValue |= nssutil_argSlotFlagTable[i].value;
+ }
+ }
+ }
+ PORT_Free(flags);
+ return retValue;
+}
+
+
+/* parse a single slot specific parameter */
+static void
+nssutil_argDecodeSingleSlotInfo(char *name, char *params,
+ struct NSSUTILPreSlotInfoStr *slotInfo)
+{
+ char *askpw;
+
+ slotInfo->slotID=NSSUTIL_ArgDecodeNumber(name);
+ slotInfo->defaultFlags=NSSUTIL_ArgParseSlotFlags("slotFlags",params);
+ slotInfo->timeout=NSSUTIL_ArgReadLong("timeout",params, 0, NULL);
+
+ askpw = NSSUTIL_ArgGetParamValue("askpw",params);
+ slotInfo->askpw = 0;
+
+ if (askpw) {
+ if (PORT_Strcasecmp(askpw,"every") == 0) {
+ slotInfo->askpw = -1;
+ } else if (PORT_Strcasecmp(askpw,"timeout") == 0) {
+ slotInfo->askpw = 1;
+ }
+ PORT_Free(askpw);
+ slotInfo->defaultFlags |= PK11_OWN_PW_DEFAULTS;
+ }
+ slotInfo->hasRootCerts = NSSUTIL_ArgHasFlag("rootFlags", "hasRootCerts",
+ params);
+ slotInfo->hasRootTrust = NSSUTIL_ArgHasFlag("rootFlags", "hasRootTrust",
+ params);
+}
+
+/* parse all the slot specific parameters. */
+struct NSSUTILPreSlotInfoStr *
+NSSUTIL_ArgParseSlotInfo(PRArenaPool *arena, char *slotParams, int *retCount)
+{
+ char *slotIndex;
+ struct NSSUTILPreSlotInfoStr *slotInfo = NULL;
+ int i=0,count = 0,next;
+
+ *retCount = 0;
+ if ((slotParams == NULL) || (*slotParams == 0)) return NULL;
+
+ /* first count the number of slots */
+ for (slotIndex = NSSUTIL_ArgStrip(slotParams); *slotIndex;
+ slotIndex = NSSUTIL_ArgStrip(NSSUTIL_ArgSkipParameter(slotIndex))) {
+ count++;
+ }
+
+ /* get the data structures */
+ if (arena) {
+ slotInfo = PORT_ArenaZNewArray(arena,
+ struct NSSUTILPreSlotInfoStr, count);
+ } else {
+ slotInfo = PORT_ZNewArray(struct NSSUTILPreSlotInfoStr, count);
+ }
+ if (slotInfo == NULL) return NULL;
+
+ for (slotIndex = NSSUTIL_ArgStrip(slotParams), i = 0;
+ *slotIndex && i < count ; ) {
+ char *name;
+ name = NSSUTIL_ArgGetLabel(slotIndex,&next);
+ slotIndex += next;
+
+ if (!NSSUTIL_ArgIsBlank(*slotIndex)) {
+ char *args = NSSUTIL_ArgFetchValue(slotIndex,&next);
+ slotIndex += next;
+ if (args) {
+ nssutil_argDecodeSingleSlotInfo(name,args,&slotInfo[i]);
+ i++;
+ PORT_Free(args);
+ }
+ }
+ if (name) PORT_Free(name);
+ slotIndex = NSSUTIL_ArgStrip(slotIndex);
+ }
+ *retCount = i;
+ return slotInfo;
+}
+
+/************************************************************************
+ * make a new slot specific parameter
+ */
+/* first make the slot flags */
+static char *
+nssutil_mkSlotFlags(unsigned long defaultFlags)
+{
+ char *flags=NULL;
+ int i,j;
+
+ for (i=0; i < sizeof(defaultFlags)*8; i++) {
+ if (defaultFlags & (1<<i)) {
+ char *string = NULL;
+
+ for (j=0; j < nssutil_argSlotFlagTableSize; j++) {
+ if (nssutil_argSlotFlagTable[j].value == ( 1UL << i )) {
+ string = nssutil_argSlotFlagTable[j].name;
+ break;
+ }
+ }
+ if (string) {
+ if (flags) {
+ char *tmp;
+ tmp = PR_smprintf("%s,%s",flags,string);
+ PR_smprintf_free(flags);
+ flags = tmp;
+ } else {
+ flags = PR_smprintf("%s",string);
+ }
+ }
+ }
+ }
+
+ return flags;
+}
+
+/* now make the root flags */
+#define NSSUTIL_MAX_ROOT_FLAG_SIZE sizeof("hasRootCerts")+sizeof("hasRootTrust")
+static char *
+nssutil_mkRootFlags(PRBool hasRootCerts, PRBool hasRootTrust)
+{
+ char *flags= (char *)PORT_ZAlloc(NSSUTIL_MAX_ROOT_FLAG_SIZE);
+ PRBool first = PR_TRUE;
+
+ PORT_Memset(flags,0,NSSUTIL_MAX_ROOT_FLAG_SIZE);
+ if (hasRootCerts) {
+ PORT_Strcat(flags,"hasRootCerts");
+ first = PR_FALSE;
+ }
+ if (hasRootTrust) {
+ if (!first) PORT_Strcat(flags,",");
+ PORT_Strcat(flags,"hasRootTrust");
+ first = PR_FALSE;
+ }
+ return flags;
+}
+
+/* now make a full slot string */
+char *
+NSSUTIL_MkSlotString(unsigned long slotID, unsigned long defaultFlags,
+ unsigned long timeout, unsigned char askpw_in,
+ PRBool hasRootCerts, PRBool hasRootTrust) {
+ char *askpw,*flags,*rootFlags,*slotString;
+ char *flagPair,*rootFlagsPair;
+
+ switch (askpw_in) {
+ case 0xff:
+ askpw = "every";
+ break;
+ case 1:
+ askpw = "timeout";
+ break;
+ default:
+ askpw = "any";
+ break;
+ }
+ flags = nssutil_mkSlotFlags(defaultFlags);
+ rootFlags = nssutil_mkRootFlags(hasRootCerts,hasRootTrust);
+ flagPair = nssutil_formatPair("slotFlags",flags,'\'');
+ rootFlagsPair = nssutil_formatPair("rootFlags",rootFlags,'\'');
+ if (flags) PR_smprintf_free(flags);
+ if (rootFlags) PORT_Free(rootFlags);
+ if (defaultFlags & PK11_OWN_PW_DEFAULTS) {
+ slotString = PR_smprintf("0x%08lx=[%s askpw=%s timeout=%d %s]",
+ (PRUint32)slotID,flagPair,askpw,timeout,
+ rootFlagsPair);
+ } else {
+ slotString = PR_smprintf("0x%08lx=[%s %s]",
+ (PRUint32)slotID,flagPair,rootFlagsPair);
+ }
+ nssutil_freePair(flagPair);
+ nssutil_freePair(rootFlagsPair);
+ return slotString;
+}
+
+
+/************************************************************************
+ * Parse Full module specs into: library, commonName, module parameters,
+ * and NSS specifi parameters.
+ */
+SECStatus
+NSSUTIL_ArgParseModuleSpec(char *modulespec, char **lib, char **mod,
+ char **parameters, char **nss)
+{
+ int next;
+ modulespec = NSSUTIL_ArgStrip(modulespec);
+
+ *lib = *mod = *parameters = *nss = 0;
+
+ while (*modulespec) {
+ NSSUTIL_HANDLE_STRING_ARG(modulespec,*lib,"library=",;)
+ NSSUTIL_HANDLE_STRING_ARG(modulespec,*mod,"name=",;)
+ NSSUTIL_HANDLE_STRING_ARG(modulespec,*parameters,"parameters=",;)
+ NSSUTIL_HANDLE_STRING_ARG(modulespec,*nss,"nss=",;)
+ NSSUTIL_HANDLE_FINAL_ARG(modulespec)
+ }
+ return SECSuccess;
+}
+
+/************************************************************************
+ * make a new module spec from it's components */
+char *
+NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
+ char *NSS)
+{
+ char *moduleSpec;
+ char *lib,*name,*param,*nss;
+
+ /*
+ * now the final spec
+ */
+ lib = nssutil_formatPair("library",dllName,'\"');
+ name = nssutil_formatPair("name",commonName,'\"');
+ param = nssutil_formatPair("parameters",parameters,'\"');
+ nss = nssutil_formatPair("NSS",NSS,'\"');
+ moduleSpec = PR_smprintf("%s %s %s %s", lib,name,param,nss);
+ nssutil_freePair(lib);
+ nssutil_freePair(name);
+ nssutil_freePair(param);
+ nssutil_freePair(nss);
+ return (moduleSpec);
+}
+
+
+#define NSSUTIL_ARG_FORTEZZA_FLAG "FORTEZZA"
+/******************************************************************************
+ * Parse the cipher flags from the NSS parameter
+ */
+void
+NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers,char *cipherList)
+{
+ newCiphers[0] = newCiphers[1] = 0;
+ if ((cipherList == NULL) || (*cipherList == 0)) return;
+
+ for (;*cipherList; cipherList=NSSUTIL_ArgNextFlag(cipherList)) {
+ if (PORT_Strncasecmp(cipherList,NSSUTIL_ARG_FORTEZZA_FLAG,
+ sizeof(NSSUTIL_ARG_FORTEZZA_FLAG)-1) == 0) {
+ newCiphers[0] |= SECMOD_FORTEZZA_FLAG;
+ }
+
+ /* add additional flags here as necessary */
+ /* direct bit mapping escape */
+ if (*cipherList == 0) {
+ if (cipherList[1] == 'l') {
+ newCiphers[1] |= atoi(&cipherList[2]);
+ } else {
+ newCiphers[0] |= atoi(&cipherList[2]);
+ }
+ }
+ }
+}
+
+
+/*********************************************************************
+ * make NSS parameter...
+ */
+/* First make NSS specific flags */
+#define MAX_FLAG_SIZE sizeof("internal")+sizeof("FIPS")+sizeof("moduleDB")+\
+ sizeof("moduleDBOnly")+sizeof("critical")
+static char *
+nssutil_mkNSSFlags(PRBool internal, PRBool isFIPS,
+ PRBool isModuleDB, PRBool isModuleDBOnly, PRBool isCritical)
+{
+ char *flags = (char *)PORT_ZAlloc(MAX_FLAG_SIZE);
+ PRBool first = PR_TRUE;
+
+ PORT_Memset(flags,0,MAX_FLAG_SIZE);
+ if (internal) {
+ PORT_Strcat(flags,"internal");
+ first = PR_FALSE;
+ }
+ if (isFIPS) {
+ if (!first) PORT_Strcat(flags,",");
+ PORT_Strcat(flags,"FIPS");
+ first = PR_FALSE;
+ }
+ if (isModuleDB) {
+ if (!first) PORT_Strcat(flags,",");
+ PORT_Strcat(flags,"moduleDB");
+ first = PR_FALSE;
+ }
+ if (isModuleDBOnly) {
+ if (!first) PORT_Strcat(flags,",");
+ PORT_Strcat(flags,"moduleDBOnly");
+ first = PR_FALSE;
+ }
+ if (isCritical) {
+ if (!first) PORT_Strcat(flags,",");
+ PORT_Strcat(flags,"critical");
+ first = PR_FALSE;
+ }
+ return flags;
+}
+
+
+/* construct the NSS cipher flags */
+static char *
+nssutil_mkCipherFlags(unsigned long ssl0, unsigned long ssl1)
+{
+ char *cipher = NULL;
+ int i;
+
+ for (i=0; i < sizeof(ssl0)*8; i++) {
+ if (ssl0 & (1<<i)) {
+ char *string;
+ if ((1<<i) == SECMOD_FORTEZZA_FLAG) {
+ string = PR_smprintf("%s",NSSUTIL_ARG_FORTEZZA_FLAG);
+ } else {
+ string = PR_smprintf("0h0x%08x",1<<i);
+ }
+ if (cipher) {
+ char *tmp;
+ tmp = PR_smprintf("%s,%s",cipher,string);
+ PR_smprintf_free(cipher);
+ PR_smprintf_free(string);
+ cipher = tmp;
+ } else {
+ cipher = string;
+ }
+ }
+ }
+ for (i=0; i < sizeof(ssl0)*8; i++) {
+ if (ssl1 & (1<<i)) {
+ if (cipher) {
+ char *tmp;
+ tmp = PR_smprintf("%s,0l0x%08x",cipher,1<<i);
+ PR_smprintf_free(cipher);
+ cipher = tmp;
+ } else {
+ cipher = PR_smprintf("0l0x%08x",1<<i);
+ }
+ }
+ }
+
+ return cipher;
+}
+
+/* Assemble a full NSS string. */
+char *
+NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal,
+ PRBool isFIPS, PRBool isModuleDB, PRBool isModuleDBOnly,
+ PRBool isCritical, unsigned long trustOrder,
+ unsigned long cipherOrder, unsigned long ssl0, unsigned long ssl1)
+{
+ int slotLen, i;
+ char *slotParams, *ciphers, *nss, *nssFlags, *tmp;
+ char *trustOrderPair,*cipherOrderPair,*slotPair,*cipherPair,*flagPair;
+
+
+ /* now let's build up the string
+ * first the slot infos
+ */
+ slotLen=0;
+ for (i=0; i < (int)slotCount; i++) {
+ slotLen += PORT_Strlen(slotStrings[i])+1;
+ }
+ slotLen += 1; /* space for the final NULL */
+
+ slotParams = (char *)PORT_ZAlloc(slotLen);
+ PORT_Memset(slotParams,0,slotLen);
+ for (i=0; i < (int)slotCount; i++) {
+ PORT_Strcat(slotParams,slotStrings[i]);
+ PORT_Strcat(slotParams," ");
+ PR_smprintf_free(slotStrings[i]);
+ slotStrings[i]=NULL;
+ }
+
+ /*
+ * now the NSS structure
+ */
+ nssFlags = nssutil_mkNSSFlags(internal,isFIPS,isModuleDB,isModuleDBOnly,
+ isCritical);
+ /* for now only the internal module is critical */
+ ciphers = nssutil_mkCipherFlags(ssl0, ssl1);
+
+ trustOrderPair = nssutil_formatIntPair("trustOrder",trustOrder,
+ NSSUTIL_DEFAULT_TRUST_ORDER);
+ cipherOrderPair = nssutil_formatIntPair("cipherOrder",cipherOrder,
+ NSSUTIL_DEFAULT_CIPHER_ORDER);
+ slotPair=nssutil_formatPair("slotParams",slotParams,'{'); /* } */
+ if (slotParams) PORT_Free(slotParams);
+ cipherPair=nssutil_formatPair("ciphers",ciphers,'\'');
+ if (ciphers) PR_smprintf_free(ciphers);
+ flagPair=nssutil_formatPair("Flags",nssFlags,'\'');
+ if (nssFlags) PORT_Free(nssFlags);
+ nss = PR_smprintf("%s %s %s %s %s",trustOrderPair,
+ cipherOrderPair,slotPair,cipherPair,flagPair);
+ nssutil_freePair(trustOrderPair);
+ nssutil_freePair(cipherOrderPair);
+ nssutil_freePair(slotPair);
+ nssutil_freePair(cipherPair);
+ nssutil_freePair(flagPair);
+ tmp = NSSUTIL_ArgStrip(nss);
+ if (*tmp == '\0') {
+ PR_smprintf_free(nss);
+ nss = NULL;
+ }
+ return nss;
+}
+
+/*****************************************************************************
+ *
+ * Private calls for use by softoken and utilmod.c
+ */
+
+#define SQLDB "sql:"
+#define EXTERNDB "extern:"
+#define LEGACY "dbm:"
+#define MULTIACCESS "multiaccess:"
+#define SECMOD_DB "secmod.db"
+const char *
+_NSSUTIL_EvaluateConfigDir(const char *configdir,
+ NSSDBType *pdbType, char **appName)
+{
+ NSSDBType dbType;
+ *appName = NULL;
+/* force the default */
+#ifdef NSS_DISABLE_DBM
+ dbType = NSS_DB_TYPE_SQL;
+#else
+ dbType = NSS_DB_TYPE_LEGACY;
+#endif
+ if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS)-1) == 0) {
+ char *cdir;
+ dbType = NSS_DB_TYPE_MULTIACCESS;
+
+ *appName = PORT_Strdup(configdir+sizeof(MULTIACCESS)-1);
+ if (*appName == NULL) {
+ return configdir;
+ }
+ cdir = *appName;
+ while (*cdir && *cdir != ':') {
+ cdir++;
+ }
+ if (*cdir == ':') {
+ *cdir = 0;
+ cdir++;
+ }
+ configdir = cdir;
+ } else if (PORT_Strncmp(configdir, SQLDB, sizeof(SQLDB)-1) == 0) {
+ dbType = NSS_DB_TYPE_SQL;
+ configdir = configdir + sizeof(SQLDB) -1;
+ } else if (PORT_Strncmp(configdir, EXTERNDB, sizeof(EXTERNDB)-1) == 0) {
+ dbType = NSS_DB_TYPE_EXTERN;
+ configdir = configdir + sizeof(EXTERNDB) -1;
+ } else if (PORT_Strncmp(configdir, LEGACY, sizeof(LEGACY)-1) == 0) {
+ dbType = NSS_DB_TYPE_LEGACY;
+ configdir = configdir + sizeof(LEGACY) -1;
+ } else {
+ /* look up the default from the environment */
+ char *defaultType = PR_GetEnv("NSS_DEFAULT_DB_TYPE");
+ if (defaultType != NULL) {
+ if (PORT_Strncmp(defaultType, SQLDB, sizeof(SQLDB)-2) == 0) {
+ dbType = NSS_DB_TYPE_SQL;
+ } else if (PORT_Strncmp(defaultType,EXTERNDB,sizeof(EXTERNDB)-2)==0) {
+ dbType = NSS_DB_TYPE_EXTERN;
+ } else if (PORT_Strncmp(defaultType, LEGACY, sizeof(LEGACY)-2) == 0) {
+ dbType = NSS_DB_TYPE_LEGACY;
+ }
+ }
+ }
+ /* if the caller has already set a type, don't change it */
+ if (*pdbType == NSS_DB_TYPE_NONE) {
+ *pdbType = dbType;
+ }
+ return configdir;
+}
+
+char *
+_NSSUTIL_GetSecmodName(char *param, NSSDBType *dbType, char **appName,
+ char **filename, PRBool *rw)
+{
+ int next;
+ char *configdir = NULL;
+ char *secmodName = NULL;
+ char *value = NULL;
+ char *save_params = param;
+ const char *lconfigdir;
+ PRBool noModDB = PR_FALSE;
+ param = NSSUTIL_ArgStrip(param);
+
+
+ while (*param) {
+ NSSUTIL_HANDLE_STRING_ARG(param,configdir,"configDir=",;)
+ NSSUTIL_HANDLE_STRING_ARG(param,secmodName,"secmod=",;)
+ NSSUTIL_HANDLE_FINAL_ARG(param)
+ }
+
+ *rw = PR_TRUE;
+ if (NSSUTIL_ArgHasFlag("flags","readOnly",save_params)) {
+ *rw = PR_FALSE;
+ }
+
+ if (!secmodName || *secmodName == '\0') {
+ if (secmodName) PORT_Free(secmodName);
+ secmodName = PORT_Strdup(SECMOD_DB);
+ }
+
+ *filename = secmodName;
+ lconfigdir = _NSSUTIL_EvaluateConfigDir(configdir, dbType, appName);
+
+ if (NSSUTIL_ArgHasFlag("flags","noModDB",save_params)) {
+ /* there isn't a module db, don't load the legacy support */
+ noModDB = PR_TRUE;
+ *dbType = NSS_DB_TYPE_SQL;
+ PORT_Free(*filename);
+ *filename = NULL;
+ *rw = PR_FALSE;
+ }
+
+ /* only use the renamed secmod for legacy databases */
+ if ((*dbType != NSS_DB_TYPE_LEGACY) &&
+ (*dbType != NSS_DB_TYPE_MULTIACCESS)) {
+ secmodName="pkcs11.txt";
+ }
+
+ if (noModDB) {
+ value = NULL;
+ } else if (lconfigdir && lconfigdir[0] != '\0') {
+ value = PR_smprintf("%s" NSSUTIL_PATH_SEPARATOR "%s",
+ lconfigdir,secmodName);
+ } else {
+ value = PR_smprintf("%s",secmodName);
+ }
+ if (configdir) PORT_Free(configdir);
+ return value;
+}
+
+
diff --git a/lib/util/utilpars.h b/lib/util/utilpars.h
new file mode 100644
index 000000000..414dae36b
--- /dev/null
+++ b/lib/util/utilpars.h
@@ -0,0 +1,56 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _UTILPARS_H_
+#define _UTILPARS_H_ 1
+
+#include "utilparst.h"
+#include "plarena.h"
+
+/* handle a module db request */
+char ** NSSUTIL_DoModuleDBFunction(unsigned long function,char *parameters, void *args);
+
+/* parsing functions */
+char *NSSUTIL_ArgFetchValue(char *string, int *pcount);
+char *NSSUTIL_ArgStrip(char *c);
+char *NSSUTIL_ArgGetParamValue(char *paramName,char *parameters);
+char *NSSUTIL_ArgSkipParameter(char *string);
+char *NSSUTIL_ArgGetLabel(char *inString, int *next);
+long NSSUTIL_ArgDecodeNumber(char *num);
+PRBool NSSUTIL_ArgIsBlank(char c);
+PRBool NSSUTIL_ArgHasFlag(char *label, char *flag, char *parameters);
+long NSSUTIL_ArgReadLong(char *label,char *params, long defValue,
+ PRBool *isdefault);
+
+/* quoting functions */
+int NSSUTIL_EscapeSize(const char *string, char quote);
+char *NSSUTIL_Escape(const char *string, char quote);
+int NSSUTIL_QuoteSize(const char *string, char quote);
+char *NSSUTIL_Quote(const char *string, char quote);
+int NSSUTIL_DoubleEscapeSize(const char *string, char quote1, char quote2);
+char *NSSUTIL_DoubleEscape(const char *string, char quote1, char quote2);
+
+unsigned long NSSUTIL_ArgParseSlotFlags(char *label,char *params);
+struct NSSUTILPreSlotInfoStr *NSSUTIL_ArgParseSlotInfo(PRArenaPool *arena,
+ char *slotParams, int *retCount);
+char * NSSUTIL_MkSlotString(unsigned long slotID, unsigned long defaultFlags,
+ unsigned long timeout, unsigned char askpw_in,
+ PRBool hasRootCerts, PRBool hasRootTrust);
+SECStatus NSSUTIL_ArgParseModuleSpec(char *modulespec, char **lib, char **mod,
+ char **parameters, char **nss);
+char *NSSUTIL_MkModuleSpec(char *dllName, char *commonName,
+ char *parameters, char *NSS);
+void NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers,char *cipherList);
+char * NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal,
+ PRBool isFIPS, PRBool isModuleDB, PRBool isModuleDBOnly,
+ PRBool isCritical, unsigned long trustOrder,
+ unsigned long cipherOrder, unsigned long ssl0, unsigned long ssl1);
+
+/*
+ * private functions for softoken.
+ */
+char * _NSSUTIL_GetSecmodName(char *param, NSSDBType *dbType, char **appName, char **filename,PRBool *rw);
+const char *_NSSUTIL_EvaluateConfigDir(const char *configdir, NSSDBType *dbType, char **app);
+
+#endif /* _UTILPARS_H_ */
diff --git a/lib/util/utilparst.h b/lib/util/utilparst.h
new file mode 100644
index 000000000..01d87addf
--- /dev/null
+++ b/lib/util/utilparst.h
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef UTILPARS_T_H
+#define UTILPARS_T_H 1
+#include "pkcs11t.h"
+
+/*
+ * macros to handle parsing strings of blank sparated arguments.
+ * Several NSSUTIL_HANDLE_STRING() macros should be places one after another with no intervening
+ * code. The first ones have precedence over the later ones. The last Macro should be
+ * NSSUTIL_HANDLE_FINAL_ARG.
+ *
+ * param is the input parameters. On exit param will point to the next parameter to parse. If the
+ * last paramter has been returned, param points to a null byte (*param = '0');
+ * target is the location to store any data aquired from the parameter. Caller is responsible to free this data.
+ * value is the string value of the parameter.
+ * command is any commands you need to run to help process the parameter's data.
+ */
+#define NSSUTIL_HANDLE_STRING_ARG(param,target,value,command) \
+ if (PORT_Strncasecmp(param,value,sizeof(value)-1) == 0) { \
+ param += sizeof(value)-1; \
+ if (target) PORT_Free(target); \
+ target = NSSUTIL_ArgFetchValue(param,&next); \
+ param += next; \
+ command ;\
+ } else
+
+#define NSSUTIL_HANDLE_FINAL_ARG(param) \
+ { param = NSSUTIL_ArgSkipParameter(param); } param = NSSUTIL_ArgStrip(param);
+
+#define NSSUTIL_PATH_SEPARATOR "/"
+
+/* default module configuration strings */
+#define NSSUTIL_DEFAULT_INTERNAL_INIT1 \
+ "library= name=\"NSS Internal PKCS #11 Module\" parameters="
+#define NSSUTIL_DEFAULT_INTERNAL_INIT2 \
+ " NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={"
+#define NSSUTIL_DEFAULT_INTERNAL_INIT3 \
+ " askpw=any timeout=30})\""
+#define NSSUTIL_DEFAULT_SFTKN_FLAGS \
+ "slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512]"
+
+#define NSSUTIL_DEFAULT_CIPHER_ORDER 0
+#define NSSUTIL_DEFAULT_TRUST_ORDER 50
+#define NSSUTIL_ARG_ESCAPE '\\'
+
+
+/* hold slot default flags until we initialize a slot. This structure is only
+ * useful between the time we define a module (either by hand or from the
+ * database) and the time the module is loaded. Not reference counted */
+struct NSSUTILPreSlotInfoStr {
+ CK_SLOT_ID slotID; /* slot these flags are for */
+ unsigned long defaultFlags; /* bit mask of default implementation this slot
+ * provides */
+ int askpw; /* slot specific password bits */
+ long timeout; /* slot specific timeout value */
+ char hasRootCerts; /* is this the root cert PKCS #11 module? */
+ char hasRootTrust; /* is this the root cert PKCS #11 module? */
+ int reserved0[2];
+ void *reserved1[2];
+};
+
+
+/*
+ * private functions for softoken.
+ */
+typedef enum {
+ NSS_DB_TYPE_NONE= 0,
+ NSS_DB_TYPE_SQL,
+ NSS_DB_TYPE_EXTERN,
+ NSS_DB_TYPE_LEGACY,
+ NSS_DB_TYPE_MULTIACCESS
+} NSSDBType;
+
+#endif /* UTILPARS_T_H */
diff --git a/lib/util/utilrename.h b/lib/util/utilrename.h
new file mode 100644
index 000000000..1aea3d284
--- /dev/null
+++ b/lib/util/utilrename.h
@@ -0,0 +1,162 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * utilrename.h - rename symbols moved from libnss3 to libnssutil3
+ *
+ */
+
+#ifndef _LIBUTIL_H_
+#define _LIBUTIL_H_ _LIBUTIL_H__Util
+
+#ifdef USE_UTIL_DIRECTLY
+
+/* functions moved from libnss3 */
+#define ATOB_AsciiToData ATOB_AsciiToData_Util
+#define ATOB_ConvertAsciiToItem ATOB_ConvertAsciiToItem_Util
+#define BTOA_ConvertItemToAscii BTOA_ConvertItemToAscii_Util
+#define BTOA_DataToAscii BTOA_DataToAscii_Util
+#define CERT_GenTime2FormattedAscii CERT_GenTime2FormattedAscii_Util
+#define DER_AsciiToTime DER_AsciiToTime_Util
+#define DER_DecodeTimeChoice DER_DecodeTimeChoice_Util
+#define DER_Encode DER_Encode_Util
+#define DER_EncodeTimeChoice DER_EncodeTimeChoice_Util
+#define DER_GeneralizedDayToAscii DER_GeneralizedDayToAscii_Util
+#define DER_GeneralizedTimeToTime DER_GeneralizedTimeToTime_Util
+#define DER_GetInteger DER_GetInteger_Util
+#define DER_Lengths DER_Lengths_Util
+#define DER_TimeChoiceDayToAscii DER_TimeChoiceDayToAscii_Util
+#define DER_TimeToGeneralizedTime DER_TimeToGeneralizedTime_Util
+#define DER_TimeToGeneralizedTimeArena DER_TimeToGeneralizedTimeArena_Util
+#define DER_TimeToUTCTime DER_TimeToUTCTime_Util
+#define DER_UTCDayToAscii DER_UTCDayToAscii_Util
+#define DER_UTCTimeToAscii DER_UTCTimeToAscii_Util
+#define DER_UTCTimeToTime DER_UTCTimeToTime_Util
+#define NSS_PutEnv NSS_PutEnv_Util
+#define NSSBase64_DecodeBuffer NSSBase64_DecodeBuffer_Util
+#define NSSBase64_EncodeItem NSSBase64_EncodeItem_Util
+#define NSSBase64Decoder_Create NSSBase64Decoder_Create_Util
+#define NSSBase64Decoder_Destroy NSSBase64Decoder_Destroy_Util
+#define NSSBase64Decoder_Update NSSBase64Decoder_Update_Util
+#define NSSBase64Encoder_Create NSSBase64Encoder_Create_Util
+#define NSSBase64Encoder_Destroy NSSBase64Encoder_Destroy_Util
+#define NSSBase64Encoder_Update NSSBase64Encoder_Update_Util
+#define NSSRWLock_Destroy NSSRWLock_Destroy_Util
+#define NSSRWLock_HaveWriteLock NSSRWLock_HaveWriteLock_Util
+#define NSSRWLock_LockRead NSSRWLock_LockRead_Util
+#define NSSRWLock_LockWrite NSSRWLock_LockWrite_Util
+#define NSSRWLock_New NSSRWLock_New_Util
+#define NSSRWLock_UnlockRead NSSRWLock_UnlockRead_Util
+#define NSSRWLock_UnlockWrite NSSRWLock_UnlockWrite_Util
+#define PORT_Alloc PORT_Alloc_Util
+#define PORT_ArenaAlloc PORT_ArenaAlloc_Util
+#define PORT_ArenaGrow PORT_ArenaGrow_Util
+#define PORT_ArenaMark PORT_ArenaMark_Util
+#define PORT_ArenaRelease PORT_ArenaRelease_Util
+#define PORT_ArenaStrdup PORT_ArenaStrdup_Util
+#define PORT_ArenaUnmark PORT_ArenaUnmark_Util
+#define PORT_ArenaZAlloc PORT_ArenaZAlloc_Util
+#define PORT_Free PORT_Free_Util
+#define PORT_FreeArena PORT_FreeArena_Util
+#define PORT_GetError PORT_GetError_Util
+#define PORT_NewArena PORT_NewArena_Util
+#define PORT_Realloc PORT_Realloc_Util
+#define PORT_SetError PORT_SetError_Util
+#define PORT_SetUCS2_ASCIIConversionFunction PORT_SetUCS2_ASCIIConversionFunction_Util
+#define PORT_SetUCS2_UTF8ConversionFunction PORT_SetUCS2_UTF8ConversionFunction_Util
+#define PORT_SetUCS4_UTF8ConversionFunction PORT_SetUCS4_UTF8ConversionFunction_Util
+#define PORT_Strdup PORT_Strdup_Util
+#define PORT_UCS2_ASCIIConversion PORT_UCS2_ASCIIConversion_Util
+#define PORT_UCS2_UTF8Conversion PORT_UCS2_UTF8Conversion_Util
+#define PORT_ZAlloc PORT_ZAlloc_Util
+#define PORT_ZFree PORT_ZFree_Util
+#define SEC_ASN1Decode SEC_ASN1Decode_Util
+#define SEC_ASN1DecodeInteger SEC_ASN1DecodeInteger_Util
+#define SEC_ASN1DecodeItem SEC_ASN1DecodeItem_Util
+#define SEC_ASN1DecoderAbort SEC_ASN1DecoderAbort_Util
+#define SEC_ASN1DecoderClearFilterProc SEC_ASN1DecoderClearFilterProc_Util
+#define SEC_ASN1DecoderClearNotifyProc SEC_ASN1DecoderClearNotifyProc_Util
+#define SEC_ASN1DecoderFinish SEC_ASN1DecoderFinish_Util
+#define SEC_ASN1DecoderSetFilterProc SEC_ASN1DecoderSetFilterProc_Util
+#define SEC_ASN1DecoderSetNotifyProc SEC_ASN1DecoderSetNotifyProc_Util
+#define SEC_ASN1DecoderStart SEC_ASN1DecoderStart_Util
+#define SEC_ASN1DecoderUpdate SEC_ASN1DecoderUpdate_Util
+#define SEC_ASN1Encode SEC_ASN1Encode_Util
+#define SEC_ASN1EncodeInteger SEC_ASN1EncodeInteger_Util
+#define SEC_ASN1EncodeItem SEC_ASN1EncodeItem_Util
+#define SEC_ASN1EncoderAbort SEC_ASN1EncoderAbort_Util
+#define SEC_ASN1EncoderClearNotifyProc SEC_ASN1EncoderClearNotifyProc_Util
+#define SEC_ASN1EncoderClearStreaming SEC_ASN1EncoderClearStreaming_Util
+#define SEC_ASN1EncoderClearTakeFromBuf SEC_ASN1EncoderClearTakeFromBuf_Util
+#define SEC_ASN1EncoderFinish SEC_ASN1EncoderFinish_Util
+#define SEC_ASN1EncoderSetNotifyProc SEC_ASN1EncoderSetNotifyProc_Util
+#define SEC_ASN1EncoderSetStreaming SEC_ASN1EncoderSetStreaming_Util
+#define SEC_ASN1EncoderSetTakeFromBuf SEC_ASN1EncoderSetTakeFromBuf_Util
+#define SEC_ASN1EncoderStart SEC_ASN1EncoderStart_Util
+#define SEC_ASN1EncoderUpdate SEC_ASN1EncoderUpdate_Util
+#define SEC_ASN1EncodeUnsignedInteger SEC_ASN1EncodeUnsignedInteger_Util
+#define SEC_ASN1LengthLength SEC_ASN1LengthLength_Util
+#define SEC_QuickDERDecodeItem SEC_QuickDERDecodeItem_Util
+#define SECITEM_AllocItem SECITEM_AllocItem_Util
+#define SECITEM_ArenaDupItem SECITEM_ArenaDupItem_Util
+#define SECITEM_CompareItem SECITEM_CompareItem_Util
+#define SECITEM_CopyItem SECITEM_CopyItem_Util
+#define SECITEM_DupItem SECITEM_DupItem_Util
+#define SECITEM_FreeItem SECITEM_FreeItem_Util
+#define SECITEM_ItemsAreEqual SECITEM_ItemsAreEqual_Util
+#define SECITEM_ZfreeItem SECITEM_ZfreeItem_Util
+#define SECOID_AddEntry SECOID_AddEntry_Util
+#define SECOID_CompareAlgorithmID SECOID_CompareAlgorithmID_Util
+#define SECOID_CopyAlgorithmID SECOID_CopyAlgorithmID_Util
+#define SECOID_DestroyAlgorithmID SECOID_DestroyAlgorithmID_Util
+#define SECOID_FindOID SECOID_FindOID_Util
+#define SECOID_FindOIDByTag SECOID_FindOIDByTag_Util
+#define SECOID_FindOIDTag SECOID_FindOIDTag_Util
+#define SECOID_FindOIDTagDescription SECOID_FindOIDTagDescription_Util
+#define SECOID_GetAlgorithmTag SECOID_GetAlgorithmTag_Util
+#define SECOID_SetAlgorithmID SECOID_SetAlgorithmID_Util
+#define SGN_CompareDigestInfo SGN_CompareDigestInfo_Util
+#define SGN_CopyDigestInfo SGN_CopyDigestInfo_Util
+#define SGN_CreateDigestInfo SGN_CreateDigestInfo_Util
+#define SGN_DestroyDigestInfo SGN_DestroyDigestInfo_Util
+
+/* templates moved from libnss3 */
+#define NSS_Get_SEC_AnyTemplate NSS_Get_SEC_AnyTemplate_Util
+#define NSS_Get_SEC_BitStringTemplate NSS_Get_SEC_BitStringTemplate_Util
+#define NSS_Get_SEC_BMPStringTemplate NSS_Get_SEC_BMPStringTemplate_Util
+#define NSS_Get_SEC_BooleanTemplate NSS_Get_SEC_BooleanTemplate_Util
+#define NSS_Get_SEC_GeneralizedTimeTemplate NSS_Get_SEC_GeneralizedTimeTemplate_Util
+#define NSS_Get_SEC_IA5StringTemplate NSS_Get_SEC_IA5StringTemplate_Util
+#define NSS_Get_SEC_IntegerTemplate NSS_Get_SEC_IntegerTemplate_Util
+#define NSS_Get_SEC_NullTemplate NSS_Get_SEC_NullTemplate_Util
+#define NSS_Get_SEC_ObjectIDTemplate NSS_Get_SEC_ObjectIDTemplate_Util
+#define NSS_Get_SEC_OctetStringTemplate NSS_Get_SEC_OctetStringTemplate_Util
+#define NSS_Get_SEC_PointerToAnyTemplate NSS_Get_SEC_PointerToAnyTemplate_Util
+#define NSS_Get_SEC_PointerToOctetStringTemplate NSS_Get_SEC_PointerToOctetStringTemplate_Util
+#define NSS_Get_SEC_SetOfAnyTemplate NSS_Get_SEC_SetOfAnyTemplate_Util
+#define NSS_Get_SEC_UTCTimeTemplate NSS_Get_SEC_UTCTimeTemplate_Util
+#define NSS_Get_SEC_UTF8StringTemplate NSS_Get_SEC_UTF8StringTemplate_Util
+#define NSS_Get_SECOID_AlgorithmIDTemplate NSS_Get_SECOID_AlgorithmIDTemplate_Util
+#define NSS_Get_sgn_DigestInfoTemplate NSS_Get_sgn_DigestInfoTemplate_Util
+#define SEC_AnyTemplate SEC_AnyTemplate_Util
+#define SEC_BitStringTemplate SEC_BitStringTemplate_Util
+#define SEC_BMPStringTemplate SEC_BMPStringTemplate_Util
+#define SEC_BooleanTemplate SEC_BooleanTemplate_Util
+#define SEC_GeneralizedTimeTemplate SEC_GeneralizedTimeTemplate_Util
+#define SEC_IA5StringTemplate SEC_IA5StringTemplate_Util
+#define SEC_IntegerTemplate SEC_IntegerTemplate_Util
+#define SEC_NullTemplate SEC_NullTemplate_Util
+#define SEC_ObjectIDTemplate SEC_ObjectIDTemplate_Util
+#define SEC_OctetStringTemplate SEC_OctetStringTemplate_Util
+#define SEC_PointerToAnyTemplate SEC_PointerToAnyTemplate_Util
+#define SEC_PointerToOctetStringTemplate SEC_PointerToOctetStringTemplate_Util
+#define SEC_SetOfAnyTemplate SEC_SetOfAnyTemplate_Util
+#define SEC_UTCTimeTemplate SEC_UTCTimeTemplate_Util
+#define SEC_UTF8StringTemplate SEC_UTF8StringTemplate_Util
+#define SECOID_AlgorithmIDTemplate SECOID_AlgorithmIDTemplate_Util
+#define sgn_DigestInfoTemplate sgn_DigestInfoTemplate_Util
+
+#endif /* USE_UTIL_DIRECTLY */
+
+#endif /* _LIBUTIL_H_ */