diff options
Diffstat (limited to 'security/nss/lib/util')
74 files changed, 25642 insertions, 0 deletions
diff --git a/security/nss/lib/util/Makefile b/security/nss/lib/util/Makefile new file mode 100644 index 000000000..97ec9345e --- /dev/null +++ b/security/nss/lib/util/Makefile @@ -0,0 +1,50 @@ +#! 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 diff --git a/security/nss/lib/util/SECerrs.h b/security/nss/lib/util/SECerrs.h new file mode 100644 index 000000000..6d6f1b868 --- /dev/null +++ b/security/nss/lib/util/SECerrs.h @@ -0,0 +1,551 @@ +/* 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/security/nss/lib/util/base64.h b/security/nss/lib/util/base64.h new file mode 100644 index 000000000..ddc2db600 --- /dev/null +++ b/security/nss/lib/util/base64.h @@ -0,0 +1,41 @@ +/* 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. + */ +#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/security/nss/lib/util/ciferfam.h b/security/nss/lib/util/ciferfam.h new file mode 100644 index 000000000..559e92f1d --- /dev/null +++ b/security/nss/lib/util/ciferfam.h @@ -0,0 +1,59 @@ +/* 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 + */ + +#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" /* deprecated */ +#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/security/nss/lib/util/config.mk b/security/nss/lib/util/config.mk new file mode 100644 index 000000000..a3e720218 --- /dev/null +++ b/security/nss/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/security/nss/lib/util/derdec.c b/security/nss/lib/util/derdec.c new file mode 100644 index 000000000..2e3312b23 --- /dev/null +++ b/security/nss/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 = (int)(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/security/nss/lib/util/derenc.c b/security/nss/lib/util/derenc.c new file mode 100644 index 000000000..da9fc4e64 --- /dev/null +++ b/security/nss/lib/util/derenc.c @@ -0,0 +1,460 @@ +/* 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, 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; + 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(PLArenaPool *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/security/nss/lib/util/dersubr.c b/security/nss/lib/util/dersubr.c new file mode 100644 index 000000000..03d070ab2 --- /dev/null +++ b/security/nss/lib/util/dersubr.c @@ -0,0 +1,249 @@ +/* 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(PLArenaPool *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(PLArenaPool *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(const SECItem *it) +{ + unsigned long ival; + PRBool negative; + unsigned int len = it->len; + unsigned char *cp = it->data; + size_t lsize = sizeof(ival); + + PORT_Assert(len); + if (!len) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + return 0; + } + + negative = (PRBool)(*cp & 0x80); + ival = negative ? ~0 : 0; + + /* Ignore leading zeros/ones. */ + while (len && *cp == (unsigned char)ival) { + len--; + cp++; + } + + /* Check for overflow/underflow. */ + if (len > lsize || (len == lsize && (*cp & 0x80) != negative)) { + PORT_SetError(SEC_ERROR_BAD_DER); + return negative ? LONG_MIN : LONG_MAX; + } + + while (len--) { + ival <<= 8; + ival |= *cp++; + } + + 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/security/nss/lib/util/dertime.c b/security/nss/lib/util/dertime.c new file mode 100644 index 000000000..f58fc18b4 --- /dev/null +++ b/security/nss/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 = PR_INT64(0xff23400100d44000); +static const PRTime January1st1950 = PR_INT64(0xfffdc1f8793da000); +static const PRTime January1st2050 = PR_INT64(0x0008f81e1b098000); +static const PRTime January1st10000 = PR_INT64(0x0384440ccc736000); + +/* gmttime must contains UTC time in micro-seconds unit */ +SECStatus +DER_TimeToUTCTimeArena(PLArenaPool *arenaOpt, SECItem *dst, PRTime 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 a PRTime 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, PRTime 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(PRTime *dst, const char *string) +{ + return der_TimeStringToTime(dst, string, UTC_STRING, NULL); +} + +SECStatus +DER_UTCTimeToTime(PRTime *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(PLArenaPool *arenaOpt, SECItem *dst, PRTime 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 a PRTime 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, PRTime gmttime) +{ + return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime); +} + +SECStatus +DER_GeneralizedTimeToTime(PRTime *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; + PRUint16 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/security/nss/lib/util/eccutil.h b/security/nss/lib/util/eccutil.h new file mode 100644 index 000000000..8c627e18b --- /dev/null +++ b/security/nss/lib/util/eccutil.h @@ -0,0 +1,15 @@ +/* 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 _FREEBL_H_ +#define _FREEBL_H_ + +/* deprecated */ +typedef enum { + ECPoint_Uncompressed, + ECPoint_XOnly, + ECPoint_Undefined +} ECPointEncoding; + +#endif /* _FREEBL_H_ */ diff --git a/security/nss/lib/util/errstrs.c b/security/nss/lib/util/errstrs.c new file mode 100644 index 000000000..138ee3958 --- /dev/null +++ b/security/nss/lib/util/errstrs.c @@ -0,0 +1,41 @@ +/* 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/security/nss/lib/util/exports.gyp b/security/nss/lib/util/exports.gyp new file mode 100644 index 000000000..eb220d2db --- /dev/null +++ b/security/nss/lib/util/exports.gyp @@ -0,0 +1,67 @@ +# 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/. +{ + 'includes': [ + '../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'lib_util_exports', + 'type': 'none', + 'copies': [ + { + 'files': [ + 'base64.h', + 'ciferfam.h', + 'eccutil.h', + 'hasht.h', + 'nssb64.h', + 'nssb64t.h', + 'nssilckt.h', + 'nssilock.h', + 'nsslocks.h', + 'nssrwlk.h', + 'nssrwlkt.h', + 'nssutil.h', + 'pkcs11.h', + 'pkcs11f.h', + 'pkcs11n.h', + 'pkcs11p.h', + 'pkcs11t.h', + 'pkcs11u.h', + 'pkcs1sig.h', + 'portreg.h', + 'secasn1.h', + 'secasn1t.h', + 'seccomon.h', + 'secder.h', + 'secdert.h', + 'secdig.h', + 'secdigt.h', + 'secerr.h', + 'secitem.h', + 'secoid.h', + 'secoidt.h', + 'secport.h', + 'utilmodt.h', + 'utilpars.h', + 'utilparst.h', + 'utilrename.h' + ], + 'destination': '<(nss_public_dist_dir)/<(module)' + }, + { + 'files': [ + 'templates.c', + 'verref.h' + ], + 'destination': '<(nss_private_dist_dir)/<(module)' + } + ] + } + ], + 'variables': { + 'module': 'nss' + } +} diff --git a/security/nss/lib/util/hasht.h b/security/nss/lib/util/hasht.h new file mode 100644 index 000000000..536d34c3d --- /dev/null +++ b/security/nss/lib/util/hasht.h @@ -0,0 +1,63 @@ +/* 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 _HASHT_H_ +#define _HASHT_H_ + +#include "prtypes.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/security/nss/lib/util/manifest.mn b/security/nss/lib/util/manifest.mn new file mode 100644 index 000000000..f0a9fd0f2 --- /dev/null +++ b/security/nss/lib/util/manifest.mn @@ -0,0 +1,90 @@ +# +# 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 \ + eccutil.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 \ + pkcs1sig.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 = \ + verref.h \ + 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 \ + pkcs1sig.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/security/nss/lib/util/nssb64.h b/security/nss/lib/util/nssb64.h new file mode 100644 index 000000000..7882c3b2d --- /dev/null +++ b/security/nss/lib/util/nssb64.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/. */ + +/* + * Public prototypes for base64 encoding/decoding. + */ +#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/security/nss/lib/util/nssb64d.c b/security/nss/lib/util/nssb64d.c new file mode 100644 index 000000000..ceb0b8ca6 --- /dev/null +++ b/security/nss/lib/util/nssb64d.c @@ -0,0 +1,822 @@ +/* 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). + */ + +#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 * 0.75; +} + +/* + * 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(PLArenaPool *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/security/nss/lib/util/nssb64e.c b/security/nss/lib/util/nssb64e.c new file mode 100644 index 000000000..18b01ddac --- /dev/null +++ b/security/nss/lib/util/nssb64e.c @@ -0,0 +1,734 @@ +/* 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). + */ + +#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; + + /* This is the maximum length we support. */ + if (size > 0x3fffffff) { + return 0; + } + + 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); + if (need_length == 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + /* + * 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(PLArenaPool *arenaOpt, char *outStrOpt, + unsigned int maxOutLen, SECItem *inItem) +{ + char *out_string = outStrOpt; + PRUint32 max_out_len; + PRUint32 out_len = 0; + 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 (max_out_len == 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + 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/security/nss/lib/util/nssb64t.h b/security/nss/lib/util/nssb64t.h new file mode 100644 index 000000000..75e7877bc --- /dev/null +++ b/security/nss/lib/util/nssb64t.h @@ -0,0 +1,15 @@ +/* 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. + */ +#ifndef _NSSB64T_H_ +#define _NSSB64T_H_ + +#include "utilrename.h" +typedef struct NSSBase64DecoderStr NSSBase64Decoder; +typedef struct NSSBase64EncoderStr NSSBase64Encoder; + +#endif /* _NSSB64T_H_ */ diff --git a/security/nss/lib/util/nssilckt.h b/security/nss/lib/util/nssilckt.h new file mode 100644 index 000000000..417f96f67 --- /dev/null +++ b/security/nss/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/security/nss/lib/util/nssilock.c b/security/nss/lib/util/nssilock.c new file mode 100644 index 000000000..d76720942 --- /dev/null +++ b/security/nss/lib/util/nssilock.c @@ -0,0 +1,479 @@ +/* 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/security/nss/lib/util/nssilock.h b/security/nss/lib/util/nssilock.h new file mode 100644 index 000000000..01f666a79 --- /dev/null +++ b/security/nss/lib/util/nssilock.h @@ -0,0 +1,267 @@ +/* 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/security/nss/lib/util/nsslocks.h b/security/nss/lib/util/nsslocks.h new file mode 100644 index 000000000..6098f56a4 --- /dev/null +++ b/security/nss/lib/util/nsslocks.h @@ -0,0 +1,10 @@ +/* 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. + */ diff --git a/security/nss/lib/util/nssrwlk.c b/security/nss/lib/util/nssrwlk.c new file mode 100644 index 000000000..dbaeca24b --- /dev/null +++ b/security/nss/lib/util/nssrwlk.c @@ -0,0 +1,448 @@ +/* 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((PRUint32)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/security/nss/lib/util/nssrwlk.h b/security/nss/lib/util/nssrwlk.h new file mode 100644 index 000000000..2ae693122 --- /dev/null +++ b/security/nss/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/security/nss/lib/util/nssrwlkt.h b/security/nss/lib/util/nssrwlkt.h new file mode 100644 index 000000000..50a4112ed --- /dev/null +++ b/security/nss/lib/util/nssrwlkt.h @@ -0,0 +1,19 @@ +/* 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/security/nss/lib/util/nssutil.def b/security/nss/lib/util/nssutil.def new file mode 100644 index 000000000..e4a65726b --- /dev/null +++ b/security/nss/lib/util/nssutil.def @@ -0,0 +1,292 @@ +;+# +;+# 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.15 { # NSS Utilities 3.15 release +;+ global: +SECITEM_AllocArray; +SECITEM_DupArray; +SECITEM_FreeArray; +SECITEM_ReallocItemV2; +SECITEM_ZfreeArray; +;+ local: +;+ *; +;+}; +;+NSSUTIL_3.17.1 { # NSS Utilities 3.17.1 release +;+ global: +_SGN_VerifyPKCS1DigestInfo; +;+ local: +;+ *; +;+}; +;+NSSUTIL_3.21 { # NSS Utilities 3.21 release +;+ global: +NSSUTIL_ArgParseModuleSpecEx; +;+ local: +;+ *; +;+}; +;+NSSUTIL_3.24 { # NSS Utilities 3.24 release +;+ global: +PORT_InitCheapArena; +PORT_DestroyCheapArena; +;+ local: +;+ *; +;+}; diff --git a/security/nss/lib/util/nssutil.h b/security/nss/lib/util/nssutil.h new file mode 100644 index 000000000..bf1feae6e --- /dev/null +++ b/security/nss/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.28.6" +#define NSSUTIL_VMAJOR 3 +#define NSSUTIL_VMINOR 28 +#define NSSUTIL_VPATCH 6 +#define NSSUTIL_VBUILD 0 +#define NSSUTIL_BETA PR_FALSE + +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/security/nss/lib/util/nssutil.rc b/security/nss/lib/util/nssutil.rc new file mode 100644 index 000000000..65d4e68b2 --- /dev/null +++ b/security/nss/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/security/nss/lib/util/oidstring.c b/security/nss/lib/util/oidstring.c new file mode 100644 index 000000000..58c8be1c4 --- /dev/null +++ b/security/nss/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/security/nss/lib/util/pkcs11.h b/security/nss/lib/util/pkcs11.h new file mode 100644 index 000000000..bd9812613 --- /dev/null +++ b/security/nss/lib/util/pkcs11.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/. */ +/* + * 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/security/nss/lib/util/pkcs11f.h b/security/nss/lib/util/pkcs11f.h new file mode 100644 index 000000000..e79e1259d --- /dev/null +++ b/security/nss/lib/util/pkcs11f.h @@ -0,0 +1,812 @@ +/* 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/security/nss/lib/util/pkcs11n.h b/security/nss/lib/util/pkcs11n.h new file mode 100644 index 000000000..ebb812222 --- /dev/null +++ b/security/nss/lib/util/pkcs11n.h @@ -0,0 +1,501 @@ +/* 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_ + +/* + * 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) + +#define CKK_NSS_CHACHA20 (CKK_NSS + 4) + +/* + * 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) + +/* TLS 1.2 mechanisms */ +#define CKM_NSS_TLS_PRF_GENERAL_SHA256 (CKM_NSS + 21) +#define CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256 (CKM_NSS + 22) +#define CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256 (CKM_NSS + 23) +#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) + +/* TLS extended master secret derivation */ +#define CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE (CKM_NSS + 25) +#define CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH (CKM_NSS + 26) + +#define CKM_NSS_CHACHA20_KEY_GEN (CKM_NSS + 27) +#define CKM_NSS_CHACHA20_POLY1305 (CKM_NSS + 28) + +/* + * 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; + +typedef struct CK_NSS_AEAD_PARAMS { + CK_BYTE_PTR pNonce; + CK_ULONG ulNonceLen; + CK_BYTE_PTR pAAD; + CK_ULONG ulAADLen; + CK_ULONG ulTagLen; +} CK_NSS_AEAD_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; + +/* + * Parameter for the TLS extended master secret key derivation mechanisms: + * + * * CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE + * * CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH + * + * For the TLS 1.2 PRF, the prfHashMechanism parameter determines the hash + * function used. For earlier versions of the PRF, set the prfHashMechanism + * value to CKM_TLS_PRF. + * + * The session hash input is expected to be the output of the same hash + * function as the PRF uses (as required by draft-ietf-tls-session-hash). So + * the ulSessionHashLen member must be equal the output length of the hash + * function specified by the prfHashMechanism member (or, for pre-TLS 1.2 PRF, + * the length of concatenated MD5 and SHA-1 digests). + * + */ +typedef struct CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS { + CK_MECHANISM_TYPE prfHashMechanism; + CK_BYTE_PTR pSessionHash; + CK_ULONG ulSessionHashLen; + CK_VERSION_PTR pVersion; +} CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS; + +/* + * 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/security/nss/lib/util/pkcs11p.h b/security/nss/lib/util/pkcs11p.h new file mode 100644 index 000000000..2e904ee50 --- /dev/null +++ b/security/nss/lib/util/pkcs11p.h @@ -0,0 +1,21 @@ +/* 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/security/nss/lib/util/pkcs11t.h b/security/nss/lib/util/pkcs11t.h new file mode 100644 index 000000000..c945f314e --- /dev/null +++ b/security/nss/lib/util/pkcs11t.h @@ -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/. */ +/* 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 + +/* TLS 1.2 mechanisms are new for v2.40 */ +#define CKM_TLS12_MASTER_KEY_DERIVE 0x000003E0 +#define CKM_TLS12_KEY_AND_MAC_DERIVE 0x000003E1 +#define CKM_TLS12_MASTER_KEY_DERIVE_DH 0x000003E2 +#define CKM_TLS12_KEY_SAFE_DERIVE 0x000003E3 +#define CKM_TLS12_MAC 0x000003E4 +#define CKM_TLS_MAC 0x000003E4 +#define CKM_TLS_KDF 0x000003E5 + +#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; /* Unused. Must be set to CK_FALSE. */ + 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; + +/* TLS 1.2 is new for version 2.40 */ +typedef struct CK_TLS12_MASTER_KEY_DERIVE_PARAMS { + CK_SSL3_RANDOM_DATA RandomInfo; + CK_VERSION_PTR pVersion; + CK_MECHANISM_TYPE prfHashMechanism; +} CK_TLS12_MASTER_KEY_DERIVE_PARAMS; + +typedef CK_TLS12_MASTER_KEY_DERIVE_PARAMS CK_PTR + CK_TLS12_MASTER_KEY_DERIVE_PARAMS_PTR; + +typedef struct CK_TLS12_KEY_MAT_PARAMS { + CK_ULONG ulMacSizeInBits; + CK_ULONG ulKeySizeInBits; + CK_ULONG ulIVSizeInBits; + CK_BBOOL bIsExport; /* Unused. Must be set to CK_FALSE. */ + CK_SSL3_RANDOM_DATA RandomInfo; + CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; + CK_MECHANISM_TYPE prfHashMechanism; +} CK_TLS12_KEY_MAT_PARAMS; + +typedef CK_TLS12_KEY_MAT_PARAMS CK_PTR CK_TLS12_KEY_MAT_PARAMS_PTR; + +typedef struct CK_TLS_KDF_PARAMS { + CK_MECHANISM_TYPE prfMechanism; + CK_BYTE_PTR pLabel; + CK_ULONG ulLabelLength; + CK_SSL3_RANDOM_DATA RandomInfo; + CK_BYTE_PTR pContextData; + CK_ULONG ulContextDataLength; +} CK_TLS_KDF_PARAMS; + +typedef struct CK_TLS_MAC_PARAMS { + CK_MECHANISM_TYPE prfMechanism; + CK_ULONG ulMacLength; + CK_ULONG ulServerOrClient; +} CK_TLS_MAC_PARAMS; + +typedef CK_TLS_MAC_PARAMS CK_PTR CK_TLS_MAC_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; /* Unused. Must be set to CK_FALSE. */ + 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.1. */ +#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001 +#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411 0x00000002 +#define CKP_PKCS5_PBKD2_HMAC_SHA224 0x00000003 +#define CKP_PKCS5_PBKD2_HMAC_SHA256 0x00000004 +#define CKP_PKCS5_PBKD2_HMAC_SHA384 0x00000005 +#define CKP_PKCS5_PBKD2_HMAC_SHA512 0x00000006 +#define CKP_PKCS5_PBKD2_HMAC_SHA512_224 0x00000007 +#define CKP_PKCS5_PBKD2_HMAC_SHA512_256 0x00000008 + +/* 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/security/nss/lib/util/pkcs11u.h b/security/nss/lib/util/pkcs11u.h new file mode 100644 index 000000000..be949bcd4 --- /dev/null +++ b/security/nss/lib/util/pkcs11u.h @@ -0,0 +1,19 @@ +/* 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/security/nss/lib/util/pkcs1sig.c b/security/nss/lib/util/pkcs1sig.c new file mode 100644 index 000000000..502119aa5 --- /dev/null +++ b/security/nss/lib/util/pkcs1sig.c @@ -0,0 +1,169 @@ +/* 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 "pkcs1sig.h" +#include "hasht.h" +#include "secerr.h" +#include "secasn1t.h" +#include "secoid.h" + +typedef struct pkcs1PrefixStr pkcs1Prefix; +struct pkcs1PrefixStr { + unsigned int len; + PRUint8 *data; +}; + +typedef struct pkcs1PrefixesStr pkcs1Prefixes; +struct pkcs1PrefixesStr { + unsigned int digestLen; + pkcs1Prefix prefixWithParams; + pkcs1Prefix prefixWithoutParams; +}; + +/* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on + * the possible prefix encodings as explained below. + */ +#define MAX_PREFIX_LEN_EXCLUDING_OID 10 + +static SECStatus +encodePrefix(const SECOidData *hashOid, unsigned int digestLen, + pkcs1Prefix *prefix, PRBool withParams) +{ + /* with params coding is: + * Sequence (2 bytes) { + * Sequence (2 bytes) { + * Oid (2 bytes) { + * Oid value (derOid->oid.len) + * } + * NULL (2 bytes) + * } + * OCTECT (2 bytes); + * + * without params coding is: + * Sequence (2 bytes) { + * Sequence (2 bytes) { + * Oid (2 bytes) { + * Oid value (derOid->oid.len) + * } + * } + * OCTECT (2 bytes); + */ + + unsigned int innerSeqLen = 2 + hashOid->oid.len; + unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen; + unsigned int extra = 0; + + if (withParams) { + innerSeqLen += 2; + outerSeqLen += 2; + extra = 2; + } + + if (innerSeqLen >= 128 || + outerSeqLen >= 128 || + (outerSeqLen + 2 - digestLen) > + (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) { + /* this is actually a library failure, It shouldn't happen */ + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + prefix->len = 6 + hashOid->oid.len + extra + 2; + prefix->data = PORT_Alloc(prefix->len); + if (!prefix->data) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + + prefix->data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED; + prefix->data[1] = outerSeqLen; + prefix->data[2] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED; + prefix->data[3] = innerSeqLen; + prefix->data[4] = SEC_ASN1_OBJECT_ID; + prefix->data[5] = hashOid->oid.len; + PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len); + if (withParams) { + prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL; + prefix->data[6 + hashOid->oid.len + 1] = 0; + } + prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING; + prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen; + + return SECSuccess; +} + +SECStatus +_SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg, + const SECItem *digest, + const SECItem *dataRecoveredFromSignature, + PRBool unsafeAllowMissingParameters) +{ + SECOidData *hashOid; + pkcs1Prefixes pp; + const pkcs1Prefix *expectedPrefix; + SECStatus rv, rv2, rv3; + + if (!digest || !digest->data || + !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + hashOid = SECOID_FindOIDByTag(digestAlg); + if (hashOid == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + pp.digestLen = digest->len; + pp.prefixWithParams.data = NULL; + pp.prefixWithoutParams.data = NULL; + + rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE); + rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE); + + rv = SECSuccess; + if (rv2 != SECSuccess || rv3 != SECSuccess) { + rv = SECFailure; + } + + if (rv == SECSuccess) { + /* We don't attempt to avoid timing attacks on these comparisons because + * signature verification is a public key operation, not a private key + * operation. + */ + + if (dataRecoveredFromSignature->len == + pp.prefixWithParams.len + pp.digestLen) { + expectedPrefix = &pp.prefixWithParams; + } else if (unsafeAllowMissingParameters && + dataRecoveredFromSignature->len == + pp.prefixWithoutParams.len + pp.digestLen) { + expectedPrefix = &pp.prefixWithoutParams; + } else { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + rv = SECFailure; + } + } + + if (rv == SECSuccess) { + if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data, + expectedPrefix->len) || + memcmp(dataRecoveredFromSignature->data + expectedPrefix->len, + digest->data, digest->len)) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + rv = SECFailure; + } + } + + if (pp.prefixWithParams.data) { + PORT_Free(pp.prefixWithParams.data); + } + if (pp.prefixWithoutParams.data) { + PORT_Free(pp.prefixWithoutParams.data); + } + + return rv; +} diff --git a/security/nss/lib/util/pkcs1sig.h b/security/nss/lib/util/pkcs1sig.h new file mode 100644 index 000000000..7c52b1575 --- /dev/null +++ b/security/nss/lib/util/pkcs1sig.h @@ -0,0 +1,30 @@ +/* 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 _PKCS1SIG_H_ +#define _PKCS1SIG_H_ + +#include "hasht.h" +#include "seccomon.h" +#include "secoidt.h" + +/* SGN_VerifyPKCS1DigestInfo verifies that the length of the digest is correct + * for the given algorithm, then verifies that the recovered data from the + * PKCS#1 signature is a properly-formatted DigestInfo that identifies the + * given digest algorithm, then verifies that the digest in the DigestInfo + * matches the given digest. + * + * dataRecoveredFromSignature must be the result of calling PK11_VerifyRecover + * or equivalent. + * + * If unsafeAllowMissingParameters is true (not recommended), then a DigestInfo + * without the mandatory ASN.1 NULL parameter will also be accepted. + */ +SECStatus _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg, + const SECItem* digest, + const SECItem* dataRecoveredFromSignature, + PRBool unsafeAllowMissingParameters); + +#endif /* _PKCS1SIG_H_ */ diff --git a/security/nss/lib/util/portreg.c b/security/nss/lib/util/portreg.c new file mode 100644 index 000000000..bf77672f0 --- /dev/null +++ b/security/nss/lib/util/portreg.c @@ -0,0 +1,375 @@ +/* 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/security/nss/lib/util/portreg.h b/security/nss/lib/util/portreg.h new file mode 100644 index 000000000..14bd9e766 --- /dev/null +++ b/security/nss/lib/util/portreg.h @@ -0,0 +1,81 @@ +/* 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/security/nss/lib/util/quickder.c b/security/nss/lib/util/quickder.c new file mode 100644 index 000000000..49ff14d55 --- /dev/null +++ b/security/nss/lib/util/quickder.c @@ -0,0 +1,819 @@ +/* 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 buf_length, + unsigned int* out_data_length, + PRBool includeTag) +{ + unsigned char tag; + unsigned int used_length = 0; + unsigned int data_length = 0; + unsigned char length_field_len = 0; + unsigned char byte; + unsigned int i; + + if (used_length >= buf_length) { + /* Tag field was not found! */ + return NULL; + } + tag = buf[used_length++]; + + if (tag == 0) { + /* End-of-contents octects should not be present in DER because + DER doesn't use the indefinite length form. */ + return NULL; + } + + if ((tag & 0x1F) == 0x1F) { + /* High tag number (a tag number > 30) is not supported */ + return NULL; + } + + if (used_length >= buf_length) { + /* Length field was not found! */ + return NULL; + } + byte = buf[used_length++]; + + if (!(byte & 0x80)) { + /* Short form: The high bit is not set. */ + data_length = byte; /* clarity; we're returning a 32-bit int. */ + } else { + /* Long form. Extract the field length */ + length_field_len = byte & 0x7F; + if (length_field_len == 0) { + /* DER doesn't use the indefinite length form. */ + return NULL; + } + + if (length_field_len > sizeof(data_length)) { + /* We don't support an extended length field longer than + 4 bytes (2^32) */ + return NULL; + } + + if (length_field_len > (buf_length - used_length)) { + /* Extended length field was not found */ + return NULL; + } + + /* Iterate across the extended length field */ + for (i = 0; i < length_field_len; i++) { + byte = buf[used_length++]; + data_length = (data_length << 8) | byte; + + if (i == 0) { + PRBool too_long = PR_FALSE; + if (length_field_len == 1) { + too_long = ((byte & 0x80) == 0); /* Short form suffices */ + } else { + too_long = (byte == 0); /* This zero byte can be omitted */ + } + if (too_long) { + /* The length is longer than needed. */ + return NULL; + } + } + } + } + + if (data_length > (buf_length - used_length)) { + /* The decoded length exceeds the available buffer */ + return NULL; + } + + if (includeTag) { + data_length += used_length; + } + + *out_data_length = data_length; + 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 -= (int)(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)) { + /* 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; */ + *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, PLArenaPool* arena, PRBool checkTag); + +static SECStatus +DecodeSequence(void* dest, + const SEC_ASN1Template* templateEntry, + SECItem* src, PLArenaPool* 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, PLArenaPool* 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, PLArenaPool* 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, PLArenaPool* 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, PLArenaPool* 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, PLArenaPool* 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, PLArenaPool* 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, PLArenaPool* arena, PRBool checkTag) +{ + SECStatus rv = SECSuccess; + SECItem temp; + SECItem mark = { siBuffer, NULL, 0 }; + PRBool pop = PR_FALSE; + PRBool decode = PR_TRUE; + PRBool save = PR_FALSE; + unsigned long kind; + PRBool match = PR_TRUE; + + 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; + 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(PLArenaPool* 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/security/nss/lib/util/secalgid.c b/security/nss/lib/util/secalgid.c new file mode 100644 index 000000000..718bb03ea --- /dev/null +++ b/security/nss/lib/util/secalgid.c @@ -0,0 +1,129 @@ +/* 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(const SECAlgorithmID *id) +{ + if (id == NULL || id->algorithm.data == NULL) + return SEC_OID_UNKNOWN; + + return SECOID_FindOIDTag(&(id->algorithm)); +} + +SECStatus +SECOID_SetAlgorithmID(PLArenaPool *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(PLArenaPool *arena, SECAlgorithmID *to, + const 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/security/nss/lib/util/secasn1.h b/security/nss/lib/util/secasn1.h new file mode 100644 index 000000000..b6292cd3b --- /dev/null +++ b/security/nss/lib/util/secasn1.h @@ -0,0 +1,291 @@ +/* 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. + */ + +#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/security/nss/lib/util/secasn1d.c b/security/nss/lib/util/secasn1d.c new file mode 100644 index 000000000..797640dc4 --- /dev/null +++ b/security/nss/lib/util/secasn1d.c @@ -0,0 +1,3373 @@ +/* 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). + */ + +/* #define DEBUG_ASN1D_STATES 1 */ + +#ifdef DEBUG_ASN1D_STATES +#include <stdio.h> +#define PR_Assert sec_asn1d_Assert +#endif + +#include <limits.h> + +#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 { + PLArenaPool *our_pool; /* for our internal allocs */ + PLArenaPool *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(PLArenaPool *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(PLArenaPool *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; +} + +/* + * Helper function for sec_asn1d_prepare_for_contents. + * Checks that a value representing a number of bytes consumed can be + * subtracted from a remaining length. If so, returns PR_TRUE. + * Otherwise, sets the error SEC_ERROR_BAD_DER, indicates that there was a + * decoding error in the given SEC_ASN1DecoderContext, and returns PR_FALSE. + */ +static PRBool +sec_asn1d_check_and_subtract_length(unsigned long *remaining, + unsigned long consumed, + SEC_ASN1DecoderContext *cx) +{ + PORT_Assert(remaining); + PORT_Assert(cx); + if (!remaining || !cx) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + cx->status = decodeError; + return PR_FALSE; + } + if (*remaining < consumed) { + PORT_SetError(SEC_ERROR_BAD_DER); + cx->status = decodeError; + return PR_FALSE; + } + *remaining -= consumed; + return PR_TRUE; +} + +static void +sec_asn1d_prepare_for_contents(sec_asn1d_state *state) +{ + SECItem *item; + PLArenaPool *poolp; + unsigned long alloc_len; + sec_asn1d_state *parent; + +#ifdef DEBUG_ASN1D_STATES + { + printf("Found Length %d %s\n", state->contents_length, + state->indefinite ? "indefinite" : ""); + } +#endif + + /** + * The maximum length for a child element should be constrained to the + * length remaining in the first definite length element in the ancestor + * stack. If there is no definite length element in the ancestor stack, + * there's nothing to constrain the length of the child, so there's no + * further processing necessary. + * + * It's necessary to walk the ancestor stack, because it's possible to have + * definite length children that are part of an indefinite length element, + * which is itself part of an indefinite length element, and which is + * ultimately part of a definite length element. A simple example of this + * would be the handling of constructed OCTET STRINGs in BER encoding. + * + * This algorithm finds the first definite length element in the ancestor + * stack, if any, and if so, ensures that the length of the child element + * is consistent with the number of bytes remaining in the constraining + * ancestor element (that is, after accounting for any other sibling + * elements that may have been read). + * + * It's slightly complicated by the need to account both for integer + * underflow and overflow, as well as ensure that for indefinite length + * encodings, there's also enough space for the End-of-Contents (EOC) + * octets (Tag = 0x00, Length = 0x00, or two bytes). + */ + + /* Determine the maximum length available for this element by finding the + * first definite length ancestor, if any. */ + parent = sec_asn1d_get_enclosing_construct(state); + while (parent && parent->indefinite) { + parent = sec_asn1d_get_enclosing_construct(parent); + } + /* If parent is null, state is either the outermost state / at the top of + * the stack, or the outermost state uses indefinite length encoding. In + * these cases, there's nothing external to constrain this element, so + * there's nothing to check. */ + if (parent) { + unsigned long remaining = parent->pending; + parent = state; + do { + if (!sec_asn1d_check_and_subtract_length( + &remaining, parent->consumed, state->top) || + /* If parent->indefinite is true, parent->contents_length is + * zero and this is a no-op. */ + !sec_asn1d_check_and_subtract_length( + &remaining, parent->contents_length, state->top) || + /* If parent->indefinite is true, then ensure there is enough + * space for an EOC tag of 2 bytes. */ + (parent->indefinite && !sec_asn1d_check_and_subtract_length(&remaining, 2, state->top))) { + /* This element is larger than its enclosing element, which is + * invalid. */ + return; + } + } while ((parent = sec_asn1d_get_enclosing_construct(parent)) && + parent->indefinite); + } + + /* + * 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; + + /* + * 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) { + (void)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); + (void)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); + (void)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? */ + (void)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) { + unsigned long offset; + /* 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--; + } + } + offset = item->len; + if (state->underlying_kind == SEC_ASN1_BIT_STRING) { + // The previous bit string must have no unused bits. + if (item->len & 0x7) { + PORT_SetError(SEC_ERROR_BAD_DER); + state->top->status = decodeError; + return 0; + } + // If this is a bit string, the length is bits, not bytes. + offset = item->len >> 3; + } + if (state->underlying_kind == SEC_ASN1_BIT_STRING) { + unsigned long len_in_bits; + // Protect against overflow during the bytes-to-bits conversion. + if (len >= (ULONG_MAX >> 3) + 1) { + PORT_SetError(SEC_ERROR_BAD_DER); + state->top->status = decodeError; + return 0; + } + len_in_bits = (len << 3) - state->bit_string_unused_bits; + // Protect against overflow when computing the total length in bits. + if (UINT_MAX - item->len < len_in_bits) { + PORT_SetError(SEC_ERROR_BAD_DER); + state->top->status = decodeError; + return 0; + } + item->len += len_in_bits; + } else { + if (UINT_MAX - item->len < len) { + PORT_SetError(SEC_ERROR_BAD_DER); + state->top->status = decodeError; + return 0; + } + item->len += len; + } + PORT_Memcpy(item->data + offset, buf, 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); + 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 { + PRBool preallocatedString; + sec_asn1d_state *temp_state; + PORT_Assert(state->indefinite); + + item = (SECItem *)(child->dest); + + /** + * At this point, there's three states at play: + * child: The element that was just parsed + * state: The currently processed element + * 'parent' (aka state->parent): The enclosing construct + * of state, or NULL if this is the top-most element. + * + * This state handles both substrings of a constructed string AND + * child elements of items whose template type was that of + * SEC_ASN1_ANY, SEC_ASN1_SAVE, SEC_ASN1_ANY_CONTENTS, SEC_ASN1_SKIP + * template, as described in sec_asn1d_prepare_for_contents. For + * brevity, these will be referred to as 'string' and 'any' types. + * + * This leads to the following possibilities: + * 1: This element is an indefinite length string, part of a + * definite length string. + * 2: This element is an indefinite length string, part of an + * indefinite length string. + * 3: This element is an indefinite length any, part of a + * definite length any. + * 4: This element is an indefinite length any, part of an + * indefinite length any. + * 5: This element is an indefinite length any and does not + * meet any of the above criteria. Note that this would include + * an indefinite length string type matching an indefinite + * length any template. + * + * In Cases #1 and #3, the definite length 'parent' element will + * have allocated state->dest based on the parent elements definite + * size. During the processing of 'child', sec_asn1d_parse_leaf will + * have copied the (string, any) data directly into the offset of + * dest, as appropriate, so there's no need for this class to still + * store the child - it's already been processed. + * + * In Cases #2 and #4, dest will be set to the parent element's dest, + * but dest->data will not have been allocated yet, due to the + * indefinite length encoding. In this situation, it's necessary to + * hold onto child (and all other children) until the EOC, at which + * point, it becomes possible to compute 'state's overall length. Once + * 'state' has a computed length, this can then be fed to 'parent' (via + * this state), and then 'parent' can similarly compute the length of + * all of its children up to the EOC, which will ultimately transit to + * sec_asn1d_concat_substrings, determine the overall size needed, + * allocate, and copy the contents (of all of parent's children, which + * would include 'state', just as 'state' will have copied all of its + * children via sec_asn1d_concat_substrings) + * + * The final case, Case #5, will manifest in that item->data and + * item->len will be NULL/0, respectively, since this element was + * indefinite-length encoded. In that case, both the tag and length will + * already exist in state's subitems, via sec_asn1d_record_any_header, + * and so the contents (aka 'child') should be added to that list of + * items to concatenate in sec_asn1d_concat_substrings once the EOC + * is encountered. + * + * To distinguish #2/#4 from #1/#3, it's sufficient to walk the ancestor + * tree. If the current type is a string type, then the enclosing + * construct will be that same type (#1/#2). If the current type is an + * any type, then the enclosing construct is either an any type (#3/#4) + * or some other type (#5). Since this is BER, this nesting relationship + * between 'state' and 'parent' may go through several levels of + * constructed encoding, so continue walking the ancestor chain until a + * clear determination can be made. + * + * The variable preallocatedString is used to indicate Case #1/#3, + * indicating an in-place copy has already occurred, and Cases #2, #4, + * and #5 all have the same behaviour of adding a new substring. + */ + preallocatedString = PR_FALSE; + temp_state = state; + while (temp_state && item == temp_state->dest && temp_state->indefinite) { + sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(temp_state); + if (!parent || parent->underlying_kind != temp_state->underlying_kind) { + /* Case #5 - Either this is a top-level construct or it is part + * of some other element (e.g. a SEQUENCE), in which case, a + * new item should be allocated. */ + break; + } + if (!parent->indefinite) { + /* Cases #1 / #3 - A definite length ancestor exists, for which + * this is a substring that has already copied into dest. */ + preallocatedString = PR_TRUE; + break; + } + if (!parent->substring) { + /* Cases #2 / #4 - If the parent is not a substring, but is + * indefinite, then there's nothing further up that may have + * preallocated dest, thus child will not have already + * been copied in place, therefore it's necessary to save child + * as a subitem. */ + break; + } + temp_state = parent; + } + if (item != NULL && item->data != NULL && !preallocatedString) { + /* + * 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); + cx->their_mark = NULL; + } +#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(PLArenaPool *their_pool, void *dest, + const SEC_ASN1Template *theTemplate) +{ + PLArenaPool *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(PLArenaPool *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(PLArenaPool *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/security/nss/lib/util/secasn1e.c b/security/nss/lib/util/secasn1e.c new file mode 100644 index 000000000..fb3feef52 --- /dev/null +++ b/security/nss/lib/util/secasn1e.c @@ -0,0 +1,1568 @@ +/* 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). + */ + +#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 { + PLArenaPool *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); + (void)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) { + (void)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) { + (void)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); + (void)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) +{ + PLArenaPool *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); + + if (len > 0) { + 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(PLArenaPool *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(PLArenaPool *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(PLArenaPool *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(PLArenaPool *poolp, SECItem *dest, long value) +{ + return sec_asn1e_integer(poolp, dest, (unsigned long)value, PR_FALSE); +} + +SECItem * +SEC_ASN1EncodeUnsignedInteger(PLArenaPool *poolp, + SECItem *dest, unsigned long value) +{ + return sec_asn1e_integer(poolp, dest, value, PR_TRUE); +} diff --git a/security/nss/lib/util/secasn1t.h b/security/nss/lib/util/secasn1t.h new file mode 100644 index 000000000..0d1a6aea0 --- /dev/null +++ b/security/nss/lib/util/secasn1t.h @@ -0,0 +1,267 @@ +/* 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). + */ + +#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/security/nss/lib/util/secasn1u.c b/security/nss/lib/util/secasn1u.c new file mode 100644 index 000000000..7d086fb0d --- /dev/null +++ b/security/nss/lib/util/secasn1u.c @@ -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/. */ + +/* + * Utility routines to complement the ASN.1 encoding and decoding functions. + */ + +#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/security/nss/lib/util/seccomon.h b/security/nss/lib/util/seccomon.h new file mode 100644 index 000000000..edd5c5329 --- /dev/null +++ b/security/nss/lib/util/seccomon.h @@ -0,0 +1,91 @@ +/* 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. + */ + +#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/security/nss/lib/util/secder.h b/security/nss/lib/util/secder.h new file mode 100644 index 000000000..dbc35807d --- /dev/null +++ b/security/nss/lib/util/secder.h @@ -0,0 +1,172 @@ +/* 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 + */ + +#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(const 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 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/security/nss/lib/util/secdert.h b/security/nss/lib/util/secdert.h new file mode 100644 index 000000000..de67eafe1 --- /dev/null +++ b/security/nss/lib/util/secdert.h @@ -0,0 +1,129 @@ +/* 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 + */ + +#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/security/nss/lib/util/secdig.c b/security/nss/lib/util/secdig.c new file mode 100644 index 000000000..f4deec54b --- /dev/null +++ b/security/nss/lib/util/secdig.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 "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(PLArenaPool *poolp, SECItem *dest, SGNDigestInfo *diginfo) +{ + return SEC_ASN1EncodeItem(poolp, dest, diginfo, sgn_DigestInfoTemplate); +} + +SGNDigestInfo * +SGN_CreateDigestInfo(SECOidTag algorithm, const unsigned char *sig, + unsigned len) +{ + SGNDigestInfo *di; + SECStatus rv; + PLArenaPool *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) +{ + PLArenaPool *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(PLArenaPool *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/security/nss/lib/util/secdig.h b/security/nss/lib/util/secdig.h new file mode 100644 index 000000000..1531bf10b --- /dev/null +++ b/security/nss/lib/util/secdig.h @@ -0,0 +1,100 @@ +/* + * secdig.h - public prototypes for digest-info 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 _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, + const 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/security/nss/lib/util/secdigt.h b/security/nss/lib/util/secdigt.h new file mode 100644 index 000000000..455343467 --- /dev/null +++ b/security/nss/lib/util/secdigt.h @@ -0,0 +1,26 @@ +/* + * secdigt.h - public data structures for digest-info objects + * + * 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 _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/security/nss/lib/util/secerr.h b/security/nss/lib/util/secerr.h new file mode 100644 index 000000000..4fe1d8e38 --- /dev/null +++ b/security/nss/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/security/nss/lib/util/secitem.c b/security/nss/lib/util/secitem.c new file mode 100644 index 000000000..22c5b1f6e --- /dev/null +++ b/security/nss/lib/util/secitem.c @@ -0,0 +1,487 @@ +/* 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. + */ + +#include "seccomon.h" +#include "secitem.h" +#include "secerr.h" +#include "secport.h" + +SECItem * +SECITEM_AllocItem(PLArenaPool *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(PLArenaPool *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; +} + +SECStatus +SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item, unsigned int newlen) +{ + unsigned char *newdata = NULL; + + PORT_Assert(item); + if (!item) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (item->len == newlen) { + return SECSuccess; + } + + if (!newlen) { + if (!arena) { + PORT_Free(item->data); + } + item->data = NULL; + item->len = 0; + return SECSuccess; + } + + if (!item->data) { + /* allocate fresh block of memory */ + PORT_Assert(!item->len); + if (arena) { + newdata = PORT_ArenaAlloc(arena, newlen); + } else { + newdata = PORT_Alloc(newlen); + } + } else { + /* reallocate or adjust existing block of memory */ + if (arena) { + if (item->len > newlen) { + /* There's no need to realloc a shorter block from the arena, + * because it would result in using even more memory! + * Therefore we'll continue to use the old block and + * set the item to the shorter size. + */ + item->len = newlen; + return SECSuccess; + } + newdata = PORT_ArenaGrow(arena, item->data, item->len, newlen); + } else { + newdata = PORT_Realloc(item->data, newlen); + } + } + + if (!newdata) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + + item->len = newlen; + item->data = newdata; + 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(PLArenaPool *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(PLArenaPool *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 (array != NULL && array->items != NULL) { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return 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 { + 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); + } + } else { + if (result != NULL && array == NULL) { + PORT_Free(result); + } + } + if (array != NULL) { + array->items = NULL; + array->len = 0; + } + return NULL; +} + +static 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); + } + } + } + PORT_Free(array->items); + array->items = NULL; + array->len = 0; + + 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; + + /* Require a "from" array. + * Reject an inconsistent "from" array with NULL data and nonzero length. + * However, allow a "from" array of zero length. + */ + 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/security/nss/lib/util/secitem.h b/security/nss/lib/util/secitem.h new file mode 100644 index 000000000..5b9d0e174 --- /dev/null +++ b/security/nss/lib/util/secitem.h @@ -0,0 +1,118 @@ +/* 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 + */ + +#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); + +/* +** This is a legacy function containing bugs. It doesn't update item->len, +** and it has other issues as described in bug 298649 and bug 298938. +** However, the function is kept unchanged for consumers that might depend +** on the broken behaviour. New code should call SECITEM_ReallocItemV2. +** +** 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(/* deprecated function */ + PLArenaPool *arena, SECItem *item, + unsigned int oldlen, unsigned int newlen); + +/* +** Reallocate the data for the specified "item". If "arena" is not NULL, +** then reallocate from there, otherwise reallocate from the heap. +** If item->data is NULL, 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, and the item will remain unchanged. +** If the allocation succeeds, the item is updated and SECSuccess is returned. + */ +extern SECStatus SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item, + 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/security/nss/lib/util/secload.c b/security/nss/lib/util/secload.c new file mode 100644 index 000000000..12efd2f75 --- /dev/null +++ b/security/nss/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/security/nss/lib/util/secoid.c b/security/nss/lib/util/secoid.c new file mode 100644 index 000000000..da03b7c06 --- /dev/null +++ b/security/nss/lib/util/secoid.c @@ -0,0 +1,2306 @@ +/* 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 + */ +const char __nss_util_version[] = "Version: NSS " NSSUTIL_VERSION _DEBUG_STRING; + +/* 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 IDEA: 1.3.6.1.4.1.188.7.1.1 + */ +#define ASCOM_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0xbc +#define ASCOM_IDEA_ALG ASCOM_OID, 0x7, 0x1, 0x1 + +/* 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 x520Name[] = { X520_ATTRIBUTE_TYPE, 41 }; +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 idea_CBC[] = { ASCOM_IDEA_ALG, 2 }; +CONST_OID aes128_GCM[] = { AES, 0x6 }; +CONST_OID aes192_GCM[] = { AES, 0x1a }; +CONST_OID aes256_GCM[] = { AES, 0x2e }; +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 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 }; /* unsupported by freebl */ +CONST_OID ansiX962prime192v2[] = { ANSI_X962_GFp_OID, 0x02 }; /* unsupported by freebl */ +CONST_OID ansiX962prime192v3[] = { ANSI_X962_GFp_OID, 0x03 }; /* unsupported by freebl */ +CONST_OID ansiX962prime239v1[] = { ANSI_X962_GFp_OID, 0x04 }; /* unsupported by freebl */ +CONST_OID ansiX962prime239v2[] = { ANSI_X962_GFp_OID, 0x05 }; /* unsupported by freebl */ +CONST_OID ansiX962prime239v3[] = { ANSI_X962_GFp_OID, 0x06 }; /* unsupported by freebl */ +CONST_OID ansiX962prime256v1[] = { ANSI_X962_GFp_OID, 0x07 }; + +/* SECG prime curve OIDs */ +CONST_OID secgECsecp112r1[] = { SECG_OID, 0x06 }; /* unsupported by freebl */ +CONST_OID secgECsecp112r2[] = { SECG_OID, 0x07 }; /* unsupported by freebl */ +CONST_OID secgECsecp128r1[] = { SECG_OID, 0x1c }; /* unsupported by freebl */ +CONST_OID secgECsecp128r2[] = { SECG_OID, 0x1d }; /* unsupported by freebl */ +CONST_OID secgECsecp160k1[] = { SECG_OID, 0x09 }; /* unsupported by freebl */ +CONST_OID secgECsecp160r1[] = { SECG_OID, 0x08 }; /* unsupported by freebl */ +CONST_OID secgECsecp160r2[] = { SECG_OID, 0x1e }; /* unsupported by freebl */ +CONST_OID secgECsecp192k1[] = { SECG_OID, 0x1f }; /* unsupported by freebl */ +CONST_OID secgECsecp224k1[] = { SECG_OID, 0x20 }; /* unsupported by freebl */ +CONST_OID secgECsecp224r1[] = { SECG_OID, 0x21 }; /* unsupported by freebl */ +CONST_OID secgECsecp256k1[] = { SECG_OID, 0x0a }; /* unsupported by freebl */ +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 }; /* unsupported by freebl */ +CONST_OID ansiX962c2pnb163v2[] = { ANSI_X962_GF2m_OID, 0x02 }; /* unsupported by freebl */ +CONST_OID ansiX962c2pnb163v3[] = { ANSI_X962_GF2m_OID, 0x03 }; /* unsupported by freebl */ +CONST_OID ansiX962c2pnb176v1[] = { ANSI_X962_GF2m_OID, 0x04 }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb191v1[] = { ANSI_X962_GF2m_OID, 0x05 }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb191v2[] = { ANSI_X962_GF2m_OID, 0x06 }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb191v3[] = { ANSI_X962_GF2m_OID, 0x07 }; /* unsupported by freebl */ +CONST_OID ansiX962c2onb191v4[] = { ANSI_X962_GF2m_OID, 0x08 }; /* unsupported by freebl */ +CONST_OID ansiX962c2onb191v5[] = { ANSI_X962_GF2m_OID, 0x09 }; /* unsupported by freebl */ +CONST_OID ansiX962c2pnb208w1[] = { ANSI_X962_GF2m_OID, 0x0a }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb239v1[] = { ANSI_X962_GF2m_OID, 0x0b }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb239v2[] = { ANSI_X962_GF2m_OID, 0x0c }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb239v3[] = { ANSI_X962_GF2m_OID, 0x0d }; /* unsupported by freebl */ +CONST_OID ansiX962c2onb239v4[] = { ANSI_X962_GF2m_OID, 0x0e }; /* unsupported by freebl */ +CONST_OID ansiX962c2onb239v5[] = { ANSI_X962_GF2m_OID, 0x0f }; /* unsupported by freebl */ +CONST_OID ansiX962c2pnb272w1[] = { ANSI_X962_GF2m_OID, 0x10 }; /* unsupported by freebl */ +CONST_OID ansiX962c2pnb304w1[] = { ANSI_X962_GF2m_OID, 0x11 }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb359v1[] = { ANSI_X962_GF2m_OID, 0x12 }; /* unsupported by freebl */ +CONST_OID ansiX962c2pnb368w1[] = { ANSI_X962_GF2m_OID, 0x13 }; /* unsupported by freebl */ +CONST_OID ansiX962c2tnb431r1[] = { ANSI_X962_GF2m_OID, 0x14 }; /* unsupported by freebl */ + +/* SECG characterisitic two curve OIDs */ +CONST_OID secgECsect113r1[] = { SECG_OID, 0x04 }; /* unsupported by freebl */ +CONST_OID secgECsect113r2[] = { SECG_OID, 0x05 }; /* unsupported by freebl */ +CONST_OID secgECsect131r1[] = { SECG_OID, 0x16 }; /* unsupported by freebl */ +CONST_OID secgECsect131r2[] = { SECG_OID, 0x17 }; /* unsupported by freebl */ +CONST_OID secgECsect163k1[] = { SECG_OID, 0x01 }; /* unsupported by freebl */ +CONST_OID secgECsect163r1[] = { SECG_OID, 0x02 }; /* unsupported by freebl */ +CONST_OID secgECsect163r2[] = { SECG_OID, 0x0f }; /* unsupported by freebl */ +CONST_OID secgECsect193r1[] = { SECG_OID, 0x18 }; /* unsupported by freebl */ +CONST_OID secgECsect193r2[] = { SECG_OID, 0x19 }; /* unsupported by freebl */ +CONST_OID secgECsect233k1[] = { SECG_OID, 0x1a }; /* unsupported by freebl */ +CONST_OID secgECsect233r1[] = { SECG_OID, 0x1b }; /* unsupported by freebl */ +CONST_OID secgECsect239k1[] = { SECG_OID, 0x03 }; /* unsupported by freebl */ +CONST_OID secgECsect283k1[] = { SECG_OID, 0x10 }; /* unsupported by freebl */ +CONST_OID secgECsect283r1[] = { SECG_OID, 0x11 }; /* unsupported by freebl */ +CONST_OID secgECsect409k1[] = { SECG_OID, 0x24 }; /* unsupported by freebl */ +CONST_OID secgECsect409r1[] = { SECG_OID, 0x25 }; /* unsupported by freebl */ +CONST_OID secgECsect571k1[] = { SECG_OID, 0x26 }; /* unsupported by freebl */ +CONST_OID secgECsect571r1[] = { SECG_OID, 0x27 }; /* unsupported by freebl */ + +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 }; + +/* https://tools.ietf.org/html/draft-josefsson-pkix-newcurves-01 + * 1.3.6.1.4.1.11591.15.1 + */ +CONST_OID curve25519[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01 }; + +#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 \ + } +#define ODE(tag, desc, mech, ext) \ + { \ + { siDEROID, NULL, 0 }, tag, desc, mech, ext \ + } +#else +#define OD(oid, tag, desc, mech, ext) \ + { \ + OI(oid) \ + , tag, 0, mech, ext \ + } +#define ODE(tag, desc, mech, ext) \ + { \ + { siDEROID, NULL, 0 }, 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 */ + /* NOTE: Only P256, P384, P521, and 25519 are supported by softoken. + * Using other curves requires an appropriate token. */ + + /* 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), + OD(x520Name, SEC_OID_AVA_NAME, + "X520 Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + + OD(aes128_GCM, SEC_OID_AES_128_GCM, + "AES-128-GCM", CKM_AES_GCM, INVALID_CERT_EXTENSION), + OD(aes192_GCM, SEC_OID_AES_192_GCM, + "AES-192-GCM", CKM_AES_GCM, INVALID_CERT_EXTENSION), + OD(aes256_GCM, SEC_OID_AES_256_GCM, + "AES-256-GCM", CKM_AES_GCM, INVALID_CERT_EXTENSION), + OD(idea_CBC, SEC_OID_IDEA_CBC, + "IDEA_CBC", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + + ODE(SEC_OID_RC2_40_CBC, + "RC2-40-CBC", CKM_RC2_CBC, INVALID_CERT_EXTENSION), + ODE(SEC_OID_DES_40_CBC, + "DES-40-CBC", CKM_RC2_CBC, INVALID_CERT_EXTENSION), + ODE(SEC_OID_RC4_40, + "RC4-40", CKM_RC4, INVALID_CERT_EXTENSION), + ODE(SEC_OID_RC4_56, + "RC4-56", CKM_RC4, INVALID_CERT_EXTENSION), + ODE(SEC_OID_NULL_CIPHER, + "NULL cipher", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_HMAC_MD5, + "HMAC-MD5", CKM_MD5_HMAC, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_RSA, + "TLS RSA key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DHE_RSA, + "TLS DHE-RSA key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DHE_DSS, + "TLS DHE-DSS key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DH_RSA, + "TLS DH-RSA key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DH_DSS, + "TLS DH-DSS key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DH_ANON, + "TLS DH-ANON key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_ECDHE_ECDSA, + "TLS ECDHE-ECDSA key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_ECDHE_RSA, + "TLS ECDHE-RSA key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_ECDH_ECDSA, + "TLS ECDH-ECDSA key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_ECDH_RSA, + "TLS ECDH-RSA key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_ECDH_ANON, + "TLS ECDH-ANON key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_RSA_EXPORT, + "TLS RSA-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DHE_RSA_EXPORT, + "TLS DHE-RSA-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DHE_DSS_EXPORT, + "TLS DHE-DSS-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DH_RSA_EXPORT, + "TLS DH-RSA-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DH_DSS_EXPORT, + "TLS DH-DSS-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DH_ANON_EXPORT, + "TLS DH-ANON-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_APPLY_SSL_POLICY, + "Apply SSL policy (pseudo-OID)", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_CHACHA20_POLY1305, + "ChaCha20-Poly1305", CKM_NSS_CHACHA20_POLY1305, INVALID_CERT_EXTENSION), + + ODE(SEC_OID_TLS_ECDHE_PSK, + "TLS ECHDE-PSK key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DHE_PSK, + "TLS DHE-PSK key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + + ODE(SEC_OID_TLS_FFDHE_2048, + "TLS FFDHE 2048-bit key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_FFDHE_3072, + "TLS FFDHE 3072-bit key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_FFDHE_4096, + "TLS FFDHE 4096-bit key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_FFDHE_6144, + "TLS FFDHE 6144-bit key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_FFDHE_8192, + "TLS FFDHE 8192-bit key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS_DHE_CUSTOM, + "TLS DHE custom group key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + OD(curve25519, SEC_OID_CURVE25519, + "Curve25519", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION), + ODE(SEC_OID_TLS13_KEA_ANY, + "TLS 1.3 fake key exchange", 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)((char *)key - (char *)NULL); +} + +#define DEF_FLAGS (NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SSL_KX) +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 == '-') ? (DEF_FLAGS) : 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 & ~(DEF_FLAGS)); + } + } + } + arg = nextArg; + } + PORT_Free(myVal); /* can handle NULL argument OK */ +} + +SECStatus +SECOID_Init(void) +{ + PLHashEntry *entry; + const SECOidData *oid; + int i; + char *envVal; + +#define NSS_VERSION_VARIABLE __nss_util_version +#include "verref.h" + + if (oidhash) { + return SECSuccess; /* already initialized */ + } + + if (!PR_GetEnvSecure("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; + } + + /* turn off NSS_USE_POLICY_IN_SSL by default */ + xOids[SEC_OID_APPLY_SSL_POLICY].notPolicyFlags = NSS_USE_POLICY_IN_SSL; + + envVal = PR_GetEnvSecure("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/security/nss/lib/util/secoid.h b/security/nss/lib/util/secoid.h new file mode 100644 index 000000000..e6eaa8ce9 --- /dev/null +++ b/security/nss/lib/util/secoid.h @@ -0,0 +1,140 @@ +/* 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 + */ + +#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, + const SECAlgorithmID *src); + +/* +** Get the tag number for the given algorithm-id object. +*/ +extern SECOidTag SECOID_GetAlgorithmTag(const 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/security/nss/lib/util/secoidt.h b/security/nss/lib/util/secoidt.h new file mode 100644 index 000000000..0a40f29fd --- /dev/null +++ b/security/nss/lib/util/secoidt.h @@ -0,0 +1,540 @@ +/* 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 + */ + +#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, + + /* The 'name' attribute type in X.520 */ + SEC_OID_AVA_NAME = 317, + + SEC_OID_AES_128_GCM = 318, + SEC_OID_AES_192_GCM = 319, + SEC_OID_AES_256_GCM = 320, + SEC_OID_IDEA_CBC = 321, + + /* pseudo - OIDs */ + + SEC_OID_RC2_40_CBC = 322, + SEC_OID_DES_40_CBC = 323, + SEC_OID_RC4_40 = 324, + SEC_OID_RC4_56 = 325, + SEC_OID_NULL_CIPHER = 326, + + SEC_OID_HMAC_MD5 = 327, + + SEC_OID_TLS_RSA = 328, + SEC_OID_TLS_DHE_RSA = 329, + SEC_OID_TLS_DHE_DSS = 330, + SEC_OID_TLS_DH_RSA = 331, + SEC_OID_TLS_DH_DSS = 332, + SEC_OID_TLS_DH_ANON = 333, + SEC_OID_TLS_ECDHE_ECDSA = 334, + SEC_OID_TLS_ECDHE_RSA = 335, + SEC_OID_TLS_ECDH_ECDSA = 336, + SEC_OID_TLS_ECDH_RSA = 337, + SEC_OID_TLS_ECDH_ANON = 338, + SEC_OID_TLS_RSA_EXPORT = 339, + + SEC_OID_TLS_DHE_RSA_EXPORT = 340, + SEC_OID_TLS_DHE_DSS_EXPORT = 341, + SEC_OID_TLS_DH_RSA_EXPORT = 342, + SEC_OID_TLS_DH_DSS_EXPORT = 343, + SEC_OID_TLS_DH_ANON_EXPORT = 344, + SEC_OID_APPLY_SSL_POLICY = 345, + + SEC_OID_CHACHA20_POLY1305 = 346, + + SEC_OID_TLS_ECDHE_PSK = 347, + SEC_OID_TLS_DHE_PSK = 348, + + SEC_OID_TLS_FFDHE_2048 = 349, + SEC_OID_TLS_FFDHE_3072 = 350, + SEC_OID_TLS_FFDHE_4096 = 351, + SEC_OID_TLS_FFDHE_6144 = 352, + SEC_OID_TLS_FFDHE_8192 = 353, + SEC_OID_TLS_DHE_CUSTOM = 354, + + SEC_OID_CURVE25519 = 355, + + SEC_OID_TLS13_KEA_ANY = 356, + + 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_IN_SSL_KX 0x00000004 /* used in SSL key exchange */ +#define NSS_USE_ALG_IN_SSL 0x00000008 /* used in SSL record protocol */ +#define NSS_USE_POLICY_IN_SSL 0x00000010 /* enable policy in SSL protocol */ +#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/security/nss/lib/util/secplcy.c b/security/nss/lib/util/secplcy.c new file mode 100644 index 000000000..0c784d055 --- /dev/null +++ b/security/nss/lib/util/secplcy.c @@ -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/. */ + +#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/security/nss/lib/util/secplcy.h b/security/nss/lib/util/secplcy.h new file mode 100644 index 000000000..6a85e03f1 --- /dev/null +++ b/security/nss/lib/util/secplcy.h @@ -0,0 +1,104 @@ +/* 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/security/nss/lib/util/secport.c b/security/nss/lib/util/secport.c new file mode 100644 index 000000000..0eea0cda0 --- /dev/null +++ b/security/nss/lib/util/secport.c @@ -0,0 +1,732 @@ +/* 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 + */ + +#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" +#include "prinit.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 + +#define CHEAP_ARENAPOOL_MAGIC 0x3F16BB09 + +typedef struct PORTArenaPool_str { + PLArenaPool arena; + PRUint32 magic; + PRLock *lock; +#ifdef THREADMARK + PRThread *marking_thread; + threadmark_mark *first_mark; +#endif +} PORTArenaPool; + +/* 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; + +/* NSPR memory allocation functions (PR_Malloc, PR_Calloc, and PR_Realloc) + * use the PRUint32 type for the size parameter. Before we pass a size_t or + * unsigned long size to these functions, we need to ensure it is <= half of + * the maximum PRUint32 value to avoid truncation and catch a negative size. + */ +#define MAX_SIZE (PR_UINT32_MAX >> 1) + +void * +PORT_Alloc(size_t bytes) +{ + void *rv = NULL; + + if (bytes <= MAX_SIZE) { + /* Always allocate a non-zero amount of bytes */ + rv = PR_Malloc(bytes ? bytes : 1); + } + if (!rv) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + } + return rv; +} + +void * +PORT_Realloc(void *oldptr, size_t bytes) +{ + void *rv = NULL; + + if (bytes <= MAX_SIZE) { + rv = PR_Realloc(oldptr, bytes); + } + if (!rv) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + } + return rv; +} + +void * +PORT_ZAlloc(size_t bytes) +{ + void *rv = NULL; + + if (bytes <= MAX_SIZE) { + /* Always allocate a non-zero amount of bytes */ + rv = PR_Calloc(1, bytes ? bytes : 1); + } + if (!rv) { + 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; + + if (chunksize > MAX_SIZE) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + pool = PORT_ZNew(PORTArenaPool); + if (!pool) { + return NULL; + } + pool->magic = ARENAPOOL_MAGIC; + pool->lock = PZ_NewLock(nssILockArena); + if (!pool->lock) { + PORT_Free(pool); + return NULL; + } + PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double)); + return (&pool->arena); +} + +void +PORT_InitCheapArena(PORTCheapArenaPool *pool, unsigned long chunksize) +{ + pool->magic = CHEAP_ARENAPOOL_MAGIC; + PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double)); +} + +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_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); +} + +static PRCallOnceType setupUseFreeListOnce; +static PRBool useFreeList; + +static PRStatus +SetupUseFreeList(void) +{ + useFreeList = (PR_GetEnvSecure("NSS_DISABLE_ARENA_FREE_LIST") == NULL); + return PR_SUCCESS; +} + +/* + * 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; + + if (!pool) + return; + if (ARENAPOOL_MAGIC == pool->magic) { + len = sizeof *pool; + lock = pool->lock; + PZ_Lock(lock); + } + if (zero) { + PL_ClearArenaPool(arena, 0); + } + (void)PR_CallOnce(&setupUseFreeListOnce, &SetupUseFreeList); + if (useFreeList) { + PL_FreeArenaPool(arena); + } else { + PL_FinishArenaPool(arena); + } + PORT_ZFree(arena, len); + if (lock) { + PZ_Unlock(lock); + PZ_DestroyLock(lock); + } +} + +void +PORT_DestroyCheapArena(PORTCheapArenaPool *pool) +{ + (void)PR_CallOnce(&setupUseFreeListOnce, &SetupUseFreeList); + if (useFreeList) { + PL_FreeArenaPool(&pool->arena); + } else { + PL_FinishArenaPool(&pool->arena); + } +} + +void * +PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize) +{ + PORTArenaPool *pool = (PORTArenaPool *)arena; + PORT_Assert(newsize >= oldsize); + + if (newsize > MAX_SIZE) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + + 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; +} + +/* + * This function accesses the internals of PLArena, which is why it needs + * to use the NSPR internal macro PL_MAKE_MEM_UNDEFINED before the memset + * calls. + * + * We should move this function to NSPR as PL_ClearArenaAfterMark or add + * a PL_ARENA_CLEAR_AND_RELEASE macro. + * + * TODO: remove the #ifdef PL_MAKE_MEM_UNDEFINED tests when NSPR 4.10+ is + * widely available. + */ +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 */ +#ifdef PL_MAKE_MEM_UNDEFINED + PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark); +#endif + 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) { +#ifdef PL_MAKE_MEM_UNDEFINED + PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark); +#endif + 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); +#ifdef PL_MAKE_MEM_UNDEFINED + PL_MAKE_MEM_UNDEFINED((void *)a->base, a->avail - a->base); +#endif + 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; + + 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 */; + } + + *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; + + 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 */; + } + + *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/security/nss/lib/util/secport.h b/security/nss/lib/util/secport.h new file mode 100644 index 000000000..0f4b08f33 --- /dev/null +++ b/security/nss/lib/util/secport.h @@ -0,0 +1,287 @@ +/* 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 + */ + +#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 + +/* + * The PORT_*Arena* function signatures mostly involve PLArenaPool* arguments. + * But this is misleading! It's not actually safe to use vanilla PLArenaPools + * with them. There are two "subclasses" of PLArenaPool that should be used + * instead. + * + * - PORTArenaPool (defined in secport.c): this "subclass" is always + * heap-allocated and uses a (heap-allocated) lock to protect all accesses. + * Use PORT_NewArena() and PORT_FreeArena() to create and destroy + * PORTArenaPools. + * + * - PORTCheapArenaPool (defined here): this "subclass" can be stack-allocated + * and does not use a lock to protect accesses. This makes it cheaper but + * less general. It is best used for arena pools that (a) are hot, (b) have + * lifetimes bounded within a single function, and (c) don't need locking. + * Use PORT_InitArena() and PORT_DestroyArena() to initialize and finalize + * PORTCheapArenaPools. + * + * All the other PORT_Arena* functions will operate safely with either + * subclass. + */ +typedef struct PORTCheapArenaPool_str { + PLArenaPool arena; + PRUint32 magic; /* This is used to distinguish the two subclasses. */ +} PORTCheapArenaPool; + +SEC_BEGIN_PROTOS + +extern void *PORT_Alloc(size_t len); +extern void *PORT_Realloc(void *old, size_t len); +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 void PORT_SetError(int value); +extern int PORT_GetError(void); + +/* These functions are for use with PORTArenaPools. */ +extern PLArenaPool *PORT_NewArena(unsigned long chunksize); +extern void PORT_FreeArena(PLArenaPool *arena, PRBool zero); + +/* These functions are for use with PORTCheapArenaPools. */ +extern void PORT_InitCheapArena(PORTCheapArenaPool *arena, + unsigned long chunksize); +extern void PORT_DestroyCheapArena(PORTCheapArenaPool *arena); + +/* These functions work with both kinds of arena pool. */ +extern void *PORT_ArenaAlloc(PLArenaPool *arena, size_t size); +extern void *PORT_ArenaZAlloc(PLArenaPool *arena, size_t size); +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 +/* This runs a function that should return SECSuccess. + * Intended for NSS internal use only. + * The return value is asserted in a debug build, otherwise it is ignored. + * This is no substitute for proper error handling. It is OK only if you + * have ensured that the function cannot fail by other means such as checking + * prerequisites. In that case this can be used as a safeguard against + * unexpected changes in a function. + */ +#ifdef DEBUG +#define PORT_CheckSuccess(f) PR_ASSERT((f) == SECSuccess) +#else +#define PORT_CheckSuccess(f) (f) +#endif +#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/security/nss/lib/util/sectime.c b/security/nss/lib/util/sectime.c new file mode 100644 index 000000000..11ee5ffeb --- /dev/null +++ b/security/nss/lib/util/sectime.c @@ -0,0 +1,163 @@ +/* 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(PRTime 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(PRTime 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) +{ + PRTime 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(PLArenaPool *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/security/nss/lib/util/templates.c b/security/nss/lib/util/templates.c new file mode 100644 index 000000000..6118aeeba --- /dev/null +++ b/security/nss/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/security/nss/lib/util/utf8.c b/security/nss/lib/util/utf8.c new file mode 100644 index 000000000..7bdd71482 --- /dev/null +++ b/security/nss/lib/util/utf8.c @@ -0,0 +1,445 @@ +/* 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 "seccomon.h" +#include "secport.h" + +/* + * 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_1] & 0x80) == 0x00)) + len += 1; + else if (inBuf[i + H_0] < 0x08) + len += 2; + else if (((inBuf[i + H_0] & 0xFC) == 0xD8)) { + if (((inBufLen - i) > 2) && ((inBuf[i + 2 + H_0] & 0xFC) == 0xDC)) { + i += 2; + len += 4; + } else { + return PR_FALSE; + } + } else if ((inBuf[i + H_0] & 0xFC) == 0xDC) { + 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] & 0xFC) == 0xD8) { + int abcde, BCDE; + + PORT_Assert(((inBufLen - i) > 2) && ((inBuf[i + 2 + H_0] & 0xFC) == 0xDC)); + + /* 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; +} diff --git a/security/nss/lib/util/util.gyp b/security/nss/lib/util/util.gyp new file mode 100644 index 000000000..9f3a74b18 --- /dev/null +++ b/security/nss/lib/util/util.gyp @@ -0,0 +1,59 @@ +# 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/. +{ + 'includes': [ + '../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'nssutil', + 'type': 'static_library', + 'sources': [ + 'derdec.c', + 'derenc.c', + 'dersubr.c', + 'dertime.c', + 'errstrs.c', + 'nssb64d.c', + 'nssb64e.c', + 'nssilock.c', + 'nssrwlk.c', + 'oidstring.c', + 'pkcs1sig.c', + 'portreg.c', + 'quickder.c', + 'secalgid.c', + 'secasn1d.c', + 'secasn1e.c', + 'secasn1u.c', + 'secdig.c', + 'secitem.c', + 'secload.c', + 'secoid.c', + 'secport.c', + 'sectime.c', + 'templates.c', + 'utf8.c', + 'utilmod.c', + 'utilpars.c' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports' + ] + }, + { + 'target_name': 'nssutil3', + 'type': 'shared_library', + 'dependencies': [ + 'nssutil' + ], + 'variables': { + 'mapfile': 'nssutil.def' + } + } + ], + 'variables': { + 'module': 'nss' + } +}
\ No newline at end of file diff --git a/security/nss/lib/util/utilmod.c b/security/nss/lib/util/utilmod.c new file mode 100644 index 000000000..e05680675 --- /dev/null +++ b/security/nss/lib/util/utilmod.c @@ -0,0 +1,765 @@ +/* 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 +#ifdef XP_UNIX +#include <unistd.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#if defined(_WIN32) +#define os_open _open +#define os_fdopen _fdopen +#define os_stat _stat +#define os_truncate_open_flags _O_CREAT | _O_RDWR | _O_TRUNC +#define os_append_open_flags _O_CREAT | _O_RDWR | _O_APPEND +#define os_open_permissions_type int +#define os_open_permissions_default _S_IREAD | _S_IWRITE +#define os_stat_type struct _stat +#else +#define os_open open +#define os_fdopen fdopen +#define os_stat stat +#define os_truncate_open_flags O_CREAT | O_RDWR | O_TRUNC +#define os_append_open_flags O_CREAT | O_RDWR | O_APPEND +#define os_open_permissions_type mode_t +#define os_open_permissions_default 0600 +#define os_stat_type struct stat +#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 destination 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 baseStringLen = baseString ? PORT_Strlen(baseString) : 0; + int len = baseStringLen + 1; + char *newString; + + len += str_len; + newString = (char *)PORT_Realloc(baseString, len); + if (newString == NULL) { + PORT_Free(baseString); + return NULL; + } + PORT_Memcpy(&newString[baseStringLen], str, str_len); + newString[len - 1] = 0; + return newString; +} + +/* 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_AddSecmodDBEntry(const char *appName, + const char *filename, + const char *dbname, + const char *module, PRBool rw); + +enum lfopen_mode { lfopen_truncate, + lfopen_append }; + +FILE * +lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms) +{ + int fd; + FILE *file; + + fd = os_open(name, + (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags, + open_perms); + if (fd < 0) { + return NULL; + } + file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+"); + 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_ZFree(moduleList, useCount * sizeof(char *)); + 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_AddSecmodDBEntry(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_DeleteSecmodDBEntry(const char *appName, + const char *filename, + const char *dbname, + const char *args, + PRBool rw) +{ + /* SHDB_FIXME implement */ + os_stat_type stat_existing; + os_open_permissions_type file_mode; + 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 = 0, lib_len = 0; + 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]++; + + /* get the permissions of the existing file, or use the default */ + if (!os_stat(dbname, &stat_existing)) { + file_mode = stat_existing.st_mode; + } else { + file_mode = os_open_permissions_default; + } + + /* do we really want to use streams here */ + fd = fopen(dbname, "r"); + if (fd == NULL) + goto loser; + + fd2 = lfopen(dbname2, lfopen_truncate, file_mode); + + 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_AddSecmodDBEntry(const char *appName, + const char *filename, const char *dbname, + const char *module, PRBool rw) +{ + os_stat_type stat_existing; + os_open_permissions_type file_mode; + 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_DeleteSecmodDBEntry(appName, filename, dbname, module, rw); + + /* get the permissions of the existing file, or use the default */ + if (!os_stat(dbname, &stat_existing)) { + file_mode = stat_existing.st_mode; + } else { + file_mode = os_open_permissions_default; + } + + fd = lfopen(dbname, lfopen_append, file_mode); + 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_AddSecmodDBEntry(appName, filename, + secmod, (char *)args, rw) == SECSuccess) + ? &success + : NULL; + break; + case SECMOD_MODULE_DB_FUNCTION_DEL: + rvstr = (nssutil_DeleteSecmodDBEntry(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/security/nss/lib/util/utilmodt.h b/security/nss/lib/util/utilmodt.h new file mode 100644 index 000000000..e1555f37f --- /dev/null +++ b/security/nss/lib/util/utilmodt.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/. */ + +#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 /* also for SHA224 */ +#define SECMOD_SHA512_FLAG 0x00008000L /* also for SHA384 */ +#define SECMOD_CAMELLIA_FLAG 0x00010000L /* = PUBLIC_MECH_CAMELLIA_FLAG */ +#define SECMOD_SEED_FLAG 0x00020000L +#define SECMOD_ECC_FLAG 0x00040000L +/* 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/security/nss/lib/util/utilpars.c b/security/nss/lib/util/utilpars.c new file mode 100644 index 000000000..7116d26f3 --- /dev/null +++ b/security/nss/lib/util/utilpars.c @@ -0,0 +1,1231 @@ +/* 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; +} + +const char * +NSSUTIL_ArgStrip(const 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. + */ +const char * +NSSUTIL_ArgFindEnd(const 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(const char *string, int *pcount) +{ + const 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 + */ +const char * +NSSUTIL_ArgSkipParameter(const char *string) +{ + const 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(const char *paramName, const 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 + */ +const char * +NSSUTIL_ArgNextFlag(const 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(const char *label, const char *flag, const char *parameters) +{ + char *flags; + const char *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(const 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(const char *inString, int *next) +{ + char *name = NULL; + const 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(const char *label, const 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(PLArenaPool *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(const char *label, const char *params) +{ + char *flags; + const char *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(PLArenaPool *arena, const char *slotParams, + int *retCount) +{ + const 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; + unsigned int i; + int j; + + for (i = 0; i < sizeof(defaultFlags) * 8; i++) { + if (defaultFlags & (1UL << 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"); + } + 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_ArgParseModuleSpecEx(const char *modulespec, char **lib, char **mod, + char **parameters, char **nss, + char **config) +{ + int next; + modulespec = NSSUTIL_ArgStrip(modulespec); + + *lib = *mod = *parameters = *nss = *config = 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_STRING_ARG(modulespec, *config, "config=", ;) + NSSUTIL_HANDLE_FINAL_ARG(modulespec) + } + return SECSuccess; +} + +/************************************************************************ + * Parse Full module specs into: library, commonName, module parameters, + * and NSS specifi parameters. + */ +SECStatus +NSSUTIL_ArgParseModuleSpec(const 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_MkModuleSpecEx(char *dllName, char *commonName, char *parameters, + char *NSS, + char *config) +{ + char *moduleSpec; + char *lib, *name, *param, *nss, *conf; + + /* + * now the final spec + */ + lib = nssutil_formatPair("library", dllName, '\"'); + name = nssutil_formatPair("name", commonName, '\"'); + param = nssutil_formatPair("parameters", parameters, '\"'); + nss = nssutil_formatPair("NSS", NSS, '\"'); + if (config) { + conf = nssutil_formatPair("config", config, '\"'); + moduleSpec = PR_smprintf("%s %s %s %s %s", lib, name, param, nss, conf); + nssutil_freePair(conf); + } else { + 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); +} + +/************************************************************************ + * make a new module spec from it's components */ +char * +NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters, + char *NSS) +{ + return NSSUTIL_MkModuleSpecEx(dllName, commonName, parameters, NSS, NULL); +} + +#define NSSUTIL_ARG_FORTEZZA_FLAG "FORTEZZA" +/****************************************************************************** + * Parse the cipher flags from the NSS parameter + */ +void +NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers, const 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"); + } + return flags; +} + +/* construct the NSS cipher flags */ +static char * +nssutil_mkCipherFlags(unsigned long ssl0, unsigned long ssl1) +{ + char *cipher = NULL; + unsigned int i; + + for (i = 0; i < sizeof(ssl0) * 8; i++) { + if (ssl0 & (1UL << i)) { + char *string; + if ((1UL << i) == SECMOD_FORTEZZA_FLAG) { + string = PR_smprintf("%s", NSSUTIL_ARG_FORTEZZA_FLAG); + } else { + string = PR_smprintf("0h0x%08lx", 1UL << 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 & (1UL << i)) { + if (cipher) { + char *tmp; + tmp = PR_smprintf("%s,0l0x%08lx", cipher, 1UL << i); + PR_smprintf_free(cipher); + cipher = tmp; + } else { + cipher = PR_smprintf("0l0x%08lx", 1UL << 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; + const char *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; + PRBool checkEnvDefaultDB = PR_FALSE; + *appName = NULL; +/* force the default */ +#ifdef NSS_DISABLE_DBM + dbType = NSS_DB_TYPE_SQL; +#else + dbType = NSS_DB_TYPE_LEGACY; +#endif + if (configdir == NULL) { + checkEnvDefaultDB = PR_TRUE; + } else 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 { + checkEnvDefaultDB = PR_TRUE; + } + + /* look up the default from the environment */ + if (checkEnvDefaultDB) { + char *defaultType = PR_GetEnvSecure("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(const char *param, NSSDBType *dbType, char **appName, + char **filename, PRBool *rw) +{ + int next; + char *configdir = NULL; + char *secmodName = NULL; + char *value = NULL; + const 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) && + !NSSUTIL_ArgHasFlag("flags", "forceSecmodChoice", save_params)) { + 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/security/nss/lib/util/utilpars.h b/security/nss/lib/util/utilpars.h new file mode 100644 index 000000000..70767263a --- /dev/null +++ b/security/nss/lib/util/utilpars.h @@ -0,0 +1,63 @@ +/* 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(const char *string, int *pcount); +const char *NSSUTIL_ArgStrip(const char *c); +char *NSSUTIL_ArgGetParamValue(const char *paramName, const char *parameters); +const char *NSSUTIL_ArgSkipParameter(const char *string); +char *NSSUTIL_ArgGetLabel(const char *inString, int *next); +long NSSUTIL_ArgDecodeNumber(const char *num); +PRBool NSSUTIL_ArgIsBlank(char c); +PRBool NSSUTIL_ArgHasFlag(const char *label, const char *flag, + const char *parameters); +long NSSUTIL_ArgReadLong(const char *label, const 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(const char *label, const char *params); +struct NSSUTILPreSlotInfoStr *NSSUTIL_ArgParseSlotInfo(PLArenaPool *arena, + const 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(const char *modulespec, char **lib, + char **mod, char **parameters, char **nss); +SECStatus NSSUTIL_ArgParseModuleSpecEx(const char *modulespec, char **lib, + char **mod, char **parameters, char **nss, char **config); +char *NSSUTIL_MkModuleSpec(char *dllName, char *commonName, + char *parameters, char *NSS); +char *NSSUTIL_MkModuleSpecEx(char *dllName, char *commonName, + char *parameters, char *NSS, char *config); +void NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers, + const 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(const 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/security/nss/lib/util/utilparst.h b/security/nss/lib/util/utilparst.h new file mode 100644 index 000000000..f2148e6e3 --- /dev/null +++ b/security/nss/lib/util/utilparst.h @@ -0,0 +1,78 @@ +/* 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/security/nss/lib/util/utilrename.h b/security/nss/lib/util/utilrename.h new file mode 100644 index 000000000..1aea3d284 --- /dev/null +++ b/security/nss/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_ */ diff --git a/security/nss/lib/util/verref.h b/security/nss/lib/util/verref.h new file mode 100644 index 000000000..efbcb031c --- /dev/null +++ b/security/nss/lib/util/verref.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/. */ + +/* This header is used inline in a function to ensure that a version string + * symbol is linked in and not optimized out. A volatile reference is added to + * the variable identified by NSS_VERSION_VARIABLE. + * + * Use this as follows: + * + * #define NSS_VERSION_VARIABLE __nss_ssl_version + * #include "verref.h" + */ + +/* Suppress unused variable warnings. */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4101) +#endif +/* This works for both gcc and clang */ +#if defined(__GNUC__) && !defined(NSS_NO_GCC48) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +#ifndef NSS_VERSION_VARIABLE +#error NSS_VERSION_VARIABLE must be set before including "verref.h" +#endif +{ + extern const char NSS_VERSION_VARIABLE[]; +#if defined(__GNUC__) + __attribute__((unused)) +#endif + volatile const char _nss_version_c = NSS_VERSION_VARIABLE[0]; +} +#undef NSS_VERSION_VARIABLE + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#if defined(__GNUC__) && !defined(NSS_NO_GCC48) +#pragma GCC diagnostic pop +#endif |