/*
 *  Copyright (C) 2007 Red Hat, Inc.
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject
 *  to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 * 
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
*/

#include "prerror.h"
#include "prprf.h"

#define NSPR_ERROR_BASE			PR_NSPR_ERROR_BASE
#define NSPR_MAX_ERROR			(PR_MAX_ERROR - 1)
#define LIBSEC_ERROR_BASE		(-8192)
#define LIBSEC_MAX_ERROR		(LIBSEC_ERROR_BASE + 155)
#define LIBSSL_ERROR_BASE		(-12288)
#define LIBSSL_MAX_ERROR		(LIBSSL_ERROR_BASE + 102)

typedef struct l_error_t {
    int errorNumber;
    const char *errorString;
} l_error_t;

l_error_t nspr_errors[] = {
    {  0, "Memory allocation attempt failed" },
    {  1, "Invalid file descriptor" },
    {  2, "The operation would have blocked" },
    {  3, "Invalid memory address argument" },
    {  4, "Invalid function for file type" },
    {  5, "Invalid memory address argument" },
    {  6, "Some unknown error has occurred" },
    {  7, "Operation interrupted by another thread" },
    {  8, "Function not implemented" },
    {  9, "I/O error" },
    { 10, "I/O operation timed out" },
    { 11, "I/O operation on busy file descriptor" },
    { 12, "The directory could not be opened" },
    { 13, "Invalid function argument" },
    { 14, "Network address not available (in use?)" },
    { 15, "Network address type not supported" },
    { 16, "Already connected" },
    { 17, "Network address is invalid" },
    { 18, "Local Network address is in use" },
    { 19, "Connection refused by peer" },
    { 20, "Network address is presently unreachable" },
    { 21, "Connection attempt timed out" },
    { 22, "Network file descriptor is not connected" },
    { 23, "Failure to load dynamic library" },
    { 24, " Failure to unload dynamic library" },
    { 25, "Symbol not found in any of the loaded dynamic libraries" },
    { 26, "Insufficient system resources" },
    { 27, "A directory lookup on a network address has failed" },
    { 28, "Attempt to access a TPD key that is out of range" },
    { 29, "Process open FD table is full" },
    { 30, "System open FD table is full" },
    { 31, "Network operation attempted on non-network file descriptor" },
    { 32, "TCP-specific function attempted on a non-TCP file descriptor" },
    { 33, "TCP file descriptor is already bound" },
    { 34, "Access Denied" },
    { 35, "The requested operation is not supported by the platform" },
    { 36, "The host operating system does not support the protocol requested" },
    { 37, "Access to the remote file has been severed" },
    { 38, "The value requested is too large to be stored in the data buffer provided" },
    { 39, "TCP connection reset by peer" },
    { 40, "Unused -5960" },
    { 41, "The operation would have deadlocked" },
    { 42, "The file is already locked" },
    { 43, "Write would result in file larger than the system allows" },
    { 44, "The device for storing the file is full" },
    { 45, "Unused -5955" },
    { 46, "Unused -5954" },
    { 47, "Cannot perform a normal file operation on a directory" },
    { 48, "Symbolic link loop" },
    { 49, "File name is too long" },
    { 50, "File not found" },
    { 51, "Cannot perform directory operation on a normal file" },
    { 52, "Cannot write to a read-only file system" },
    { 53, "Cannot delete a directory that is not empty" },
    { 54, "Cannot delete or rename a file object while the file system is busy" },
    { 55, "Cannot rename a file to a file system on another device" },
    { 56, "The directory object in the file system is corrupted" },
    { 57, "Cannot create or rename a filename that already exists" },
    { 58, "Directory is full.  No additional filenames may be added" },
    { 59, "The required device was in an invalid state" },
    { 60, "The device is locked" },
    { 61, "No more entries in the directory" },
    { 62, "Encountered end of file" },
    { 63, "Seek error" },
    { 64, "The file is busy" },
    { 65, "The I/O operation was aborted" },
    { 66, "Operation is still in progress (probably a non-blocking connect)" },
    { 67, "Operation has already been initiated (probably a non-blocking connect)" },
    { 68, "The wait group is empty" },
    { 69, "Object state improper for request" },
    { 70, "Network is down" },
    { 71, "Socket shutdown" },
    { 72, "Connection aborted" },
    { 73, "Host is unreachable" },
    { 74, "The library is not loaded" },
};

l_error_t libsec_errors[] = {
    {  0, "I/O Error" },
    {  1, "Library Failure" },
    {  2, "Bad data was received" },
    {  3, "Security library: output length error" },
    {  4, "Security library has experienced an input length error" },
    {  5, "Security library: invalid arguments" },
    {  6, "Certificate contains invalid encryption or signature algorithm" },
    {  7, "Security library: invalid AVA" },
    {  8, "Certificate contains an invalid time value" },
    {  9, "Certificate is improperly DER encoded" },
    { 10, "Certificate has invalid signature" },
    { 11, "Certificate has expired" },
    { 12, "Certificate has been revoked" },
    { 13, "Certificate is signed by an unknown issuer" },
    { 14, "Invalid public key in certificate" },
    { 15, "The security password entered is incorrect" },
    { 16, "SEC_ERROR_UNUSED" },
    { 17, "Security library: no nodelock" },
    { 18, "Problem using certificate or key database" },
    { 19, "Out of Memory" },
    { 20, "Certificate is signed by an untrusted issuer" },
    { 21, "Peer's certificate has been marked as not trusted" },
    { 22, "Certificate already exists in your database" },
    { 23, "Downloaded certificate's name duplicates one already in your database" },
    { 24, "Error adding certificate to database" },
    { 25, "Error refiling the key for this certificate" },
    { 26, "The private key for this certificate cannot be found in key database" },
    { 27, "This certificate is valid" },
    { 28, "This certificate is not valid" },
    { 29, "Cert Library: No Response" },
    { 30, "The certificate issuer's certificate has expired. Check your system date and time" },
    { 31, "The CRL for the certificate's issuer has expired. Update it or check your system date and time" },
    { 32, "The CRL for the certificate's issuer has an invalid signature" },
    { 33, "New CRL has an invalid format" },
    { 34, "Certificate extension value is invalid" },
    { 35, "Certificate extension not found" },
    { 36, "Issuer certificate is invalid" },
    { 37, "Certificate path length constraint is invalid" },
    { 38, "Certificate usages field is invalid" },
    { 39, "**Internal ONLY module**" },
    { 40, "The key does not support the requested operation" },
    { 41, "Certificate contains unknown critical extension" },
    { 42, "New CRL is not later than the current one" },
    { 43, "Not encrypted or signed: you do not yet have an email certificate" },
    { 44, "Not encrypted: you do not have certificates for each of the recipients" },
    { 45, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found" },
    { 46, "Cannot decrypt: key encryption algorithm does not match your certificate" },
    { 47, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data" },
    { 48, "Unsupported or unknown key algorithm" },
    { 49, "Cannot decrypt: encrypted using a disallowed algorithm or key size" },
    { 50, "XP_Fortezza card has not been properly initialized. Please remove it and return it to your issuer" },
    { 51, "XP_No Fortezza cards Found" },
    { 52, "XP_No Fortezza card selected" },
    { 53, "XP_Please select a personality to get more info on" },
    { 54, "XP_Personality not found" },
    { 55, "XP_No more information on that Personality" },
    { 56, "XP_Invalid Pin" },
    { 57, "XP_Couldn't initialize Fortezza personalities" },
    { 58, "No KRL for this site's certificate has been found" },
    { 59, "The KRL for this site's certificate has expired" },
    { 60, "The KRL for this site's certificate has an invalid signature" },
    { 61, "The key for this site's certificate has been revoked" },
    { 62, "New KRL has an invalid format" },
    { 63, "security library: need random data" },
    { 64, "security library: no security module can perform the requested operation" },
    { 65, "The security card or token does not exist, needs to be initialized, or has been removed" },
    { 66, "security library: read-only database" },
    { 67, "No slot or token was selected" },
    { 68, "A certificate with the same nickname already exists" },
    { 69, "A key with the same nickname already exists" },
    { 70, "error while creating safe object" },
    { 71, "error while creating baggage object" },
    { 72, "Couldn't remove the principal" },
    { 73, "Couldn't delete the privilege" },
    { 74, "This principal doesn't have a certificate" },
    { 75, "Required algorithm is not allowed" },
    { 76, "Error attempting to export certificates" },
    { 77, "Error attempting to import certificates" },
    { 78, "Unable to import. Decoding error. File not valid" },
    { 79, "Unable to import. Invalid MAC. Incorrect password or corrupt file" },
    { 80, "Unable to import. MAC algorithm not supported" },
    { 81, "SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE" },
    { 82, "Unable to import. File structure is corrupt." },
    { 83, "Unable to import. Encryption algorithm not supported." },
    { 84, "Unable to import. File version not supported." },
    { 85, "SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT" },
    { 86, "Unable to import. Same nickname already exists in database." },
    { 87, "The user pressed cancel." },
    { 88, "Not imported, already in database." },
    { 89, "Message not sent." },
    { 90, "Certificate key usage inadequate for attempted operation." },
    { 91, "Certificate type not approved for application." },
    { 92, "Address in signing certificate does not match address in message headers." },
    { 93, "Unable to import. Error attempting to import private key." },
    { 94, "Unable to import. Error attempting to import certificate chain." },
    { 95, "Unable to export. Unable to locate certificate or key by nickname." },
    { 96, "Unable to export. Private Key could not be located and exported." },
    { 97, "Unable to export. Unable to write the export file." },
    { 98, "Unable to import. Unable to read the import file." },
    { 99, "Unable to export. Key database corrupt or deleted." },
    { 100, "Unable to generate public/private key pair." },
    { 101, "Password entered is invalid. Please pick a different one." },
    { 102, "Old password entered incorrectly. Please try again." },
    { 103, "Certificate nickname already in use." },
    { 104, "Peer FORTEZZA chain has a non-FORTEZZA Certificate." },
    { 105, "A sensitive key cannot be moved to the slot where it is needed." },
    { 106, "Invalid module name." },
    { 107, "Invalid module path/filename" },
    { 108, "Unable to add module" },
    { 109, "Unable to delete module" },
    { 110, "New KRL is not later than the current one." },
    { 111, "New CKL has different issuer than current CKL. Delete current CKL" },
    { 112, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name" },
    { 113, "The key revocation list for this certificate is not yet valid" },
    { 114, "The certificate revocation list for this certificate is not yet valid" },
    { 115, "The requested certificate could not be found" },
    { 116, "The signer's certificate could not be found" },
    { 117, "The location for the certificate status server has invalid format" },
    { 118, "The OCSP response cannot be fully decoded; it is of an unknown type" },
    { 119, "The OCSP server returned unexpected/invalid HTTP data" },
    { 120, "The OCSP server found the request to be corrupted or improperly formed" },
    { 121, "The OCSP server experienced an internal error" },
    { 122, "The OCSP server suggests trying again later" },
    { 123, "The OCSP server requires a signature on this request" },
    { 124, "The OCSP server has refused this request as unauthorized" },
    { 125, "The OCSP server returned an unrecognizable status" },
    { 126, "The OCSP server has no status for the certificate" },
    { 127, "You must enable OCSP before performing this operation" },
    { 128, "You must set the OCSP default responder before performing this operation" },
    { 129, "The response from the OCSP server was corrupted or improperly formed" },
    { 130, "The signer of the OCSP response is not authorized to give status for this certificate" },
    { 131, "The OCSP response is not yet valid (contains a date in the future)" },
    { 132, "The OCSP response contains out-of-date information" },
    { 133, "SEC_ERROR_DIGEST_NOT_FOUND - Digest not found in S/MIME message." },
    { 134, "SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE - Unsupported or unknown message type in S/MIME message." },
    { 135, "SEC_ERROR_MODULE_STUCK - PK11 module is stuck." },
    { 136, "SEC_ERROR_BAD_TEMPLATE - Bad template found when decoding DER." },
    { 137, "SEC_ERROR_CRL_NOT_FOUND" },
    { 138, "SEC_ERROR_REUSED_ISSUER_AND_SERIAL" },
    { 139, "SEC_ERROR_BUSY" },
    { 140, "SEC_ERROR_EXTRA_INPUT" },
    { 141, "SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE" },
    { 142, "SEC_ERROR_UNSUPPORTED_EC_POINT_FORM" },
    { 143, "SEC_ERROR_UNRECOGNIZED_OID" },
    { 144, "SEC_ERROR_OCSP_INVALID_SIGNING_CERT - OCSP signer certificate not found, not trusted or invalid." },
    { 145, "SEC_ERROR_REVOKED_CERTIFICATE_CRL - This certificate has been revoked." },
    { 146, "SEC_ERROR_REVOKED_CERTIFICATE_OCSP - This certificate has been revoked." },
    { 147, "SEC_ERROR_CRL_INVALID_VERSION" },
    { 148, "SEC_ERROR_CRL_V1_CRITICAL_EXTENSION" },
    { 149, "SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION" },
    { 150, "SEC_ERROR_UNKNOWN_OBJECT_TYPE" },
    { 151, "SEC_ERROR_INCOMPATIBLE_PKCS11" },
    { 152, "SEC_ERROR_NO_EVENT" },
    { 153, "SEC_ERROR_CRL_ALREADY_EXISTS" },
    { 154, "SEC_ERROR_NOT_INITIALIZED" },
    { 155, "SEC_ERROR_TOKEN_NOT_LOGGED_IN" }
};

l_error_t libnss_errors[] = {
    {  0, "Client does not support high-grade encryption" },
    {  1, "Client requires high-grade encryption which is not supported" },
    {  2, "No common encryption algorithm(s) with client" },
    {  3, "Unable to find the certificate or key necessary for authentication" },
    {  4, "Unable to communicate securely wih peer: peer's certificate was rejected" },
    {  5, "Unused SSL error #5" },
    {  6, "Protocol error" },
    {  7, "Protocol error" },
    {  8, "Unsupported certificate type" },
    {  9, "Client is using unsupported SSL version" },
    { 10, "Unused SSL error #10" },
    { 11, "The public key in the server's own certificate does not match its private key" },
    { 12, "Requested domain name does not match the server's certificate" },
    { 13, "SSL_ERROR_POST_WARNING" },
    { 14, "peer only supports SSL version 2, which is locally disabled" },
    { 15, "SSL has received a record with an incorrect Message Authentication Code" },
    { 16, "SSL has received an error indicating an incorrect Message Authentication Code" },
    { 17, "SSL client cannot verify your certificate" },
    { 18, "The server has rejected your certificate as revoked" },
    { 19, "The server has rejected your certificate as expired" },
    { 20, "Cannot connect: SSL is disabled" },
    { 21, "Cannot connect: SSL peer is in another Fortezza domain" },
    { 22, "An unknown SSL cipher suite has been requested" },
    { 23, "No cipher suites are present and enabled in this program" },
    { 24, "SSL received a record with bad block padding" },
    { 25, "SSL received a record that exceeded the maximum permissible length" },
    { 26, "SSL attempted to send a record that exceeded the maximum permissible length" },
    { 27, "SSL received a malformed Hello Request handshake message" },
    { 28, "SSL received a malformed Client Hello handshake message" },
    { 29, "SSL received a malformed Server Hello handshake message" },
    { 30, "SSL received a malformed Certificate handshake message" },
    { 31, "SSL received a malformed Server Key Exchange handshake message" },
    { 32, "SSL received a malformed Certificate Request handshake message" },
    { 33, "SSL received a malformed Server Hello Done handshake message" },
    { 34, "SSL received a malformed Certificate Verify handshake message" },
    { 35, "SSL received a malformed Client Key Exchange handshake message" },
    { 36, "SSL received a malformed Finished handshake message" },
    { 37, "SSL received a malformed Change Cipher Spec record" },
    { 38, "SSL received a malformed Alert record" },
    { 39, "SSL received a malformed Handshake record" },
    { 40, "SSL received a malformed Application Data record" },
    { 41, "SSL received an unexpected Hello Request handshake message" },
    { 42, "SSL received an unexpected Client Hello handshake message" },
    { 43, "SSL received an unexpected Server Hello handshake message" },
    { 44, "SSL received an unexpected Certificate handshake message" },
    { 45, "SSL received an unexpected Server Key Exchange handshake message" },
    { 46, "SSL received an unexpected Certificate Request handshake message" },
    { 47, "SSL received an unexpected Server Hello Done handshake message" },
    { 48, "SSL received an unexpected Certificate Verify handshake message" },
    { 49, "SSL received an unexpected Cllient Key Exchange handshake message" },
    { 50, "SSL received an unexpected Finished handshake message" },
    { 51, "SSL received an unexpected Change Cipher Spec record" },
    { 52, "SSL received an unexpected Alert record" },
    { 53, "SSL received an unexpected Handshake record" },
    { 54, "SSL received an unexpected Application Data record" },
    { 55, "SSL received a record with an unknown content type" },
    { 56, "SSL received a handshake message with an unknown message type" },
    { 57, "SSL received an alert record with an unknown alert description" },
    { 58, "SSL peer has closed the connection" },
    { 59, "SSL peer was not expecting a handshake message it received" },
    { 60, "SSL peer was unable to succesfully decompress an SSL record it received" },
    { 61, "SSL peer was unable to negotiate an acceptable set of security parameters" },
    { 62, "SSL peer rejected a handshake message for unacceptable content" },
    { 63, "SSL peer does not support certificates of the type it received" },
    { 64, "SSL peer had some unspecified issue with the certificate it received" },
    { 65, "SSL experienced a failure of its random number generator" },
    { 66, "Unable to digitally sign data required to verify your certificate" },
    { 67, "SSL was unable to extract the public key from the peer's certificate" },
    { 68, "Unspecified failure while processing SSL Server Key Exchange handshake" },
    { 69, "Unspecified failure while processing SSL Client Key Exchange handshake" },
    { 70, "Bulk data encryption algorithm failed in selected cipher suite" },
    { 71, "Bulk data decryption algorithm failed in selected cipher suite" },
    { 72, "Attempt to write encrypted data to underlying socket failed" },
    { 73, "MD5 digest function failed" },
    { 74, "SHA-1 digest function failed" },
    { 75, "MAC computation failed" },
    { 76, "Failure to create Symmetric Key context" },
    { 77, "Failure to unwrap the Symmetric key in Client Key Exchange message" },
    { 78, "SSL Server attempted to use domestic-grade public key with export cipher suite" },
    { 79, "PKCS11 code failed to translate an IV into a param" },
    { 80, "Failed to initialize the selected cipher suite" },
    { 81, "Failed to generate session keys for SSL session" },
    { 82, "Server has no key for the attempted key exchange algorithm" },
    { 83, "PKCS#11 token was inserted or removed while operation was in progress" },
    { 84, "No PKCS#11 token could be found to do a required operation" },
    { 85, "Cannot communicate securely with peer: no common compression algorithm(s)" },
    { 86, "Cannot initiate another SSL handshake until current handshake is complete" },
    { 87, "Received incorrect handshakes hash values from peer" },
    { 88, "The certificate provided cannot be used with the selected key exchange algorithm" },
    { 89, "There are no trusted Certificate Authorities for signing SSL client certificates" },
    { 90, "Client's SSL session ID not found in server's session cache" },
    { 91, "Peer was unable to decrypt an SSL record it received" },
    { 92, "Peer received an SSL record that was longer than is permitted" },
    { 93, "Peer does not recognize and trust the CA that issued your certificate" },
    { 94, "Peer received a valid certificate, but access was denied" },
    { 95, "Peer could not decode an SSL handshake message" },
    { 96, "Peer reports failure of signature verification or key exchange" },
    { 97, "Peer reports negotiation not in compliance with export regulations" },
    { 98, "Peer reports incompatible or unsupported protocol version" },
    { 99, "Server requires ciphers more secure than those supported by client" },
    { 100, "Peer reports it experienced an internal error" },
    { 101, "Peer user canceled handshake" },
    { 102, "Peer does not permit renegotiation of SSL security parameters" }
};

const char *nss_error(int error)
{
    static char errbuf[256];
    const char *err = NULL;

    if ((error >= NSPR_ERROR_BASE) &&
        (error <= NSPR_MAX_ERROR)) {
        err = nspr_errors[error-NSPR_ERROR_BASE].errorString;
    } else if ((error >= LIBSEC_ERROR_BASE) &&
        (error <= LIBSEC_MAX_ERROR)) {
        err = libsec_errors[error-LIBSEC_ERROR_BASE].errorString;
    } else if ((error >= LIBSSL_ERROR_BASE) &&
        (error <= LIBSSL_MAX_ERROR)) {
        err = libnss_errors[error-LIBSSL_ERROR_BASE].errorString;
    } 

    if (err) {
        PR_snprintf(errbuf, 256, "%s", err);
    } else {
        PR_snprintf(errbuf, 256, "error number %d", error);
    }

    return errbuf;
}
