diff --git a/mozilla/security/python/nss/src/NSPRerrs.h b/mozilla/security/python/nss/src/NSPRerrs.h new file mode 100644 index 00000000000..b11169847c1 --- /dev/null +++ b/mozilla/security/python/nss/src/NSPRerrs.h @@ -0,0 +1,153 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* General NSPR 2.0 errors */ +/* Caller must #include "prerror.h" */ + +ER2( PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed." ) +ER2( PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor." ) +ER2( PR_WOULD_BLOCK_ERROR, "The operation would have blocked." ) +ER2( PR_ACCESS_FAULT_ERROR, "Invalid memory address argument." ) +ER2( PR_INVALID_METHOD_ERROR, "Invalid function for file type." ) +ER2( PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument." ) +ER2( PR_UNKNOWN_ERROR, "Some unknown error has occurred." ) +ER2( PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread." ) +ER2( PR_NOT_IMPLEMENTED_ERROR, "function not implemented." ) +ER2( PR_IO_ERROR, "I/O function error." ) +ER2( PR_IO_TIMEOUT_ERROR, "I/O operation timed out." ) +ER2( PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor." ) +ER2( PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened." ) +ER2( PR_INVALID_ARGUMENT_ERROR, "Invalid function argument." ) +ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)." ) +ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported." ) +ER2( PR_IS_CONNECTED_ERROR, "Already connected." ) +ER2( PR_BAD_ADDRESS_ERROR, "Network address is invalid." ) +ER2( PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use." ) +ER2( PR_CONNECT_REFUSED_ERROR, "Connection refused by peer." ) +ER2( PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable." ) +ER2( PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out." ) +ER2( PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected." ) +ER2( PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library." ) +ER2( PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library." ) +ER2( PR_FIND_SYMBOL_ERROR, +"Symbol not found in any of the loaded dynamic libraries." ) +ER2( PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources." ) +ER2( PR_DIRECTORY_LOOKUP_ERROR, +"A directory lookup on a network address has failed." ) +ER2( PR_TPD_RANGE_ERROR, +"Attempt to access a TPD key that is out of range." ) +ER2( PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full." ) +ER2( PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full." ) +ER2( PR_NOT_SOCKET_ERROR, +"Network operation attempted on non-network file descriptor." ) +ER2( PR_NOT_TCP_SOCKET_ERROR, +"TCP-specific function attempted on a non-TCP file descriptor." ) +ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound." ) +ER2( PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied." ) +ER2( PR_OPERATION_NOT_SUPPORTED_ERROR, +"The requested operation is not supported by the platform." ) +ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR, +"The host operating system does not support the protocol requested." ) +ER2( PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed." ) +ER2( PR_BUFFER_OVERFLOW_ERROR, +"The value requested is too large to be stored in the data buffer provided." ) +ER2( PR_CONNECT_RESET_ERROR, "TCP connection reset by peer." ) +ER2( PR_RANGE_ERROR, "Unused." ) +ER2( PR_DEADLOCK_ERROR, "The operation would have deadlocked." ) +ER2( PR_FILE_IS_LOCKED_ERROR, "The file is already locked." ) +ER2( PR_FILE_TOO_BIG_ERROR, +"Write would result in file larger than the system allows." ) +ER2( PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full." ) +ER2( PR_PIPE_ERROR, "Unused." ) +ER2( PR_NO_SEEK_DEVICE_ERROR, "Unused." ) +ER2( PR_IS_DIRECTORY_ERROR, +"Cannot perform a normal file operation on a directory." ) +ER2( PR_LOOP_ERROR, "Symbolic link loop." ) +ER2( PR_NAME_TOO_LONG_ERROR, "File name is too long." ) +ER2( PR_FILE_NOT_FOUND_ERROR, "File not found." ) +ER2( PR_NOT_DIRECTORY_ERROR, +"Cannot perform directory operation on a normal file." ) +ER2( PR_READ_ONLY_FILESYSTEM_ERROR, +"Cannot write to a read-only file system." ) +ER2( PR_DIRECTORY_NOT_EMPTY_ERROR, +"Cannot delete a directory that is not empty." ) +ER2( PR_FILESYSTEM_MOUNTED_ERROR, +"Cannot delete or rename a file object while the file system is busy." ) +ER2( PR_NOT_SAME_DEVICE_ERROR, +"Cannot rename a file to a file system on another device." ) +ER2( PR_DIRECTORY_CORRUPTED_ERROR, +"The directory object in the file system is corrupted." ) +ER2( PR_FILE_EXISTS_ERROR, +"Cannot create or rename a filename that already exists." ) +ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR, +"Directory is full. No additional filenames may be added." ) +ER2( PR_INVALID_DEVICE_STATE_ERROR, +"The required device was in an invalid state." ) +ER2( PR_DEVICE_IS_LOCKED_ERROR, "The device is locked." ) +ER2( PR_NO_MORE_FILES_ERROR, "No more entries in the directory." ) +ER2( PR_END_OF_FILE_ERROR, "Encountered end of file." ) +ER2( PR_FILE_SEEK_ERROR, "Seek error." ) +ER2( PR_FILE_IS_BUSY_ERROR, "The file is busy." ) +ER2( PR_IN_PROGRESS_ERROR, +"Operation is still in progress (probably a non-blocking connect)." ) +ER2( PR_ALREADY_INITIATED_ERROR, +"Operation has already been initiated (probably a non-blocking connect)." ) + +#ifdef PR_GROUP_EMPTY_ERROR +ER2( PR_GROUP_EMPTY_ERROR, "The wait group is empty." ) +#endif + +#ifdef PR_INVALID_STATE_ERROR +ER2( PR_INVALID_STATE_ERROR, "Object state improper for request." ) +#endif + +#ifdef PR_NETWORK_DOWN_ERROR +ER2( PR_NETWORK_DOWN_ERROR, "Network is down." ) +#endif + +#ifdef PR_SOCKET_SHUTDOWN_ERROR +ER2( PR_SOCKET_SHUTDOWN_ERROR, "The socket was previously shut down." ) +#endif + +#ifdef PR_CONNECT_ABORTED_ERROR +ER2( PR_CONNECT_ABORTED_ERROR, "TCP Connection aborted." ) +#endif + +#ifdef PR_HOST_UNREACHABLE_ERROR +ER2( PR_HOST_UNREACHABLE_ERROR, "Host is unreachable." ) +#endif + +/* always last */ +ER2( PR_MAX_ERROR, "Placeholder for the end of the list" ) diff --git a/mozilla/security/python/nss/src/SECerrs.h b/mozilla/security/python/nss/src/SECerrs.h new file mode 100644 index 00000000000..bb1533686a7 --- /dev/null +++ b/mozilla/security/python/nss/src/SECerrs.h @@ -0,0 +1,521 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* 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), +"OCSP Trusted Responder Cert is invalid.") + +ER3(SEC_ERROR_OCSP_BAD_SIGNATURE, (SEC_ERROR_BASE + 157), +"OCSP response has an invalid signature.") diff --git a/mozilla/security/python/nss/src/SSLerrs.h b/mozilla/security/python/nss/src/SSLerrs.h new file mode 100644 index 00000000000..376ee83992d --- /dev/null +++ b/mozilla/security/python/nss/src/SSLerrs.h @@ -0,0 +1,386 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* SSL-specific security error codes */ +/* caller must include "sslerr.h" */ + +ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0, +"Unable to communicate securely. Peer does not support high-grade encryption.") + +ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1, +"Unable to communicate securely. Peer requires high-grade encryption which is not supported.") + +ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2, +"Cannot communicate securely with peer: no common encryption algorithm(s).") + +ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3, +"Unable to find the certificate or key necessary for authentication.") + +ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4, +"Unable to communicate securely with peer: peers's certificate was rejected.") + +/* unused (SSL_ERROR_BASE + 5),*/ + +ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6, +"The server has encountered bad data from the client.") + +ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7, +"The client has encountered bad data from the server.") + +ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8, +"Unsupported certificate type.") + +ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9, +"Peer using unsupported version of security protocol.") + +/* unused (SSL_ERROR_BASE + 10),*/ + +ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11, +"Client authentication failed: private key in key database does not match public key in certificate database.") + +ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12, +"Unable to communicate securely with peer: requested domain name does not match the server's certificate.") + +/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13), + defined in sslerr.h +*/ + +ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14), +"Peer only supports SSL version 2, which is locally disabled.") + + +ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15), +"SSL received a record with an incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16), +"SSL peer reports incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17), +"SSL peer cannot verify your certificate.") + +ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18), +"SSL peer rejected your certificate as revoked.") + +ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19), +"SSL peer rejected your certificate as expired.") + +ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20), +"Cannot connect: SSL is disabled.") + +ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21), +"Cannot connect: SSL peer is in another FORTEZZA domain.") + + +ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22), +"An unknown SSL cipher suite has been requested.") + +ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23), +"No cipher suites are present and enabled in this program.") + +ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24), +"SSL received a record with bad block padding.") + +ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25), +"SSL received a record that exceeded the maximum permissible length.") + +ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26), +"SSL attempted to send a record that exceeded the maximum permissible length.") + +/* + * Received a malformed (too long or short or invalid content) SSL handshake. + */ +ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27), +"SSL received a malformed Hello Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28), +"SSL received a malformed Client Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29), +"SSL received a malformed Server Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30), +"SSL received a malformed Certificate handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31), +"SSL received a malformed Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32), +"SSL received a malformed Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33), +"SSL received a malformed Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34), +"SSL received a malformed Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35), +"SSL received a malformed Client Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36), +"SSL received a malformed Finished handshake message.") + +/* + * Received a malformed (too long or short) SSL record. + */ +ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37), +"SSL received a malformed Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38), +"SSL received a malformed Alert record.") + +ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39), +"SSL received a malformed Handshake record.") + +ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40), +"SSL received a malformed Application Data record.") + +/* + * Received an SSL handshake that was inappropriate for the state we're in. + * E.g. Server received message from server, or wrong state in state machine. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41), +"SSL received an unexpected Hello Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42), +"SSL received an unexpected Client Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43), +"SSL received an unexpected Server Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44), +"SSL received an unexpected Certificate handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45), +"SSL received an unexpected Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46), +"SSL received an unexpected Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47), +"SSL received an unexpected Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48), +"SSL received an unexpected Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49), +"SSL received an unexpected Client Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50), +"SSL received an unexpected Finished handshake message.") + +/* + * Received an SSL record that was inappropriate for the state we're in. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51), +"SSL received an unexpected Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52), +"SSL received an unexpected Alert record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53), +"SSL received an unexpected Handshake record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54), +"SSL received an unexpected Application Data record.") + +/* + * Received record/message with unknown discriminant. + */ +ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55), +"SSL received a record with an unknown content type.") + +ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56), +"SSL received a handshake message with an unknown message type.") + +ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57), +"SSL received an alert record with an unknown alert description.") + +/* + * Received an alert reporting what we did wrong. (more alerts above) + */ +ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58), +"SSL peer has closed this connection.") + +ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59), +"SSL peer was not expecting a handshake message it received.") + +ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60), +"SSL peer was unable to successfully decompress an SSL record it received.") + +ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61), +"SSL peer was unable to negotiate an acceptable set of security parameters.") + +ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62), +"SSL peer rejected a handshake message for unacceptable content.") + +ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63), +"SSL peer does not support certificates of the type it received.") + +ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64), +"SSL peer had some unspecified issue with the certificate it received.") + + +ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65), +"SSL experienced a failure of its random number generator.") + +ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66), +"Unable to digitally sign data required to verify your certificate.") + +ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67), +"SSL was unable to extract the public key from the peer's certificate.") + +ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68), +"Unspecified failure while processing SSL Server Key Exchange handshake.") + +ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69), +"Unspecified failure while processing SSL Client Key Exchange handshake.") + +ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70), +"Bulk data encryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71), +"Bulk data decryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72), +"Attempt to write encrypted data to underlying socket failed.") + +ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73), +"MD5 digest function failed.") + +ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74), +"SHA-1 digest function failed.") + +ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75), +"MAC computation failed.") + +ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76), +"Failure to create Symmetric Key context.") + +ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77), +"Failure to unwrap the Symmetric key in Client Key Exchange message.") + +ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78), +"SSL Server attempted to use domestic-grade public key with export cipher suite.") + +ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79), +"PKCS11 code failed to translate an IV into a param.") + +ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80), +"Failed to initialize the selected cipher suite.") + +ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81), +"Client failed to generate session keys for SSL session.") + +ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82), +"Server has no key for the attempted key exchange algorithm.") + +ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83), +"PKCS#11 token was inserted or removed while operation was in progress.") + +ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84), +"No PKCS#11 token could be found to do a required operation.") + +ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85), +"Cannot communicate securely with peer: no common compression algorithm(s).") + +ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86), +"Cannot initiate another SSL handshake until current handshake is complete.") + +ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87), +"Received incorrect handshakes hash values from peer.") + +ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88), +"The certificate provided cannot be used with the selected key exchange algorithm.") + +ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89), +"No certificate authority is trusted for SSL client authentication.") + +ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90), +"Client's SSL session ID not found in server's session cache.") + +ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT , (SSL_ERROR_BASE + 91), +"Peer was unable to decrypt an SSL record it received.") + +ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT , (SSL_ERROR_BASE + 92), +"Peer received an SSL record that was longer than is permitted.") + +ER3(SSL_ERROR_UNKNOWN_CA_ALERT , (SSL_ERROR_BASE + 93), +"Peer does not recognize and trust the CA that issued your certificate.") + +ER3(SSL_ERROR_ACCESS_DENIED_ALERT , (SSL_ERROR_BASE + 94), +"Peer received a valid certificate, but access was denied.") + +ER3(SSL_ERROR_DECODE_ERROR_ALERT , (SSL_ERROR_BASE + 95), +"Peer could not decode an SSL handshake message.") + +ER3(SSL_ERROR_DECRYPT_ERROR_ALERT , (SSL_ERROR_BASE + 96), +"Peer reports failure of signature verification or key exchange.") + +ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT , (SSL_ERROR_BASE + 97), +"Peer reports negotiation not in compliance with export regulations.") + +ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT , (SSL_ERROR_BASE + 98), +"Peer reports incompatible or unsupported protocol version.") + +ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99), +"Server requires ciphers more secure than those supported by client.") + +ER3(SSL_ERROR_INTERNAL_ERROR_ALERT , (SSL_ERROR_BASE + 100), +"Peer reports it experienced an internal error.") + +ER3(SSL_ERROR_USER_CANCELED_ALERT , (SSL_ERROR_BASE + 101), +"Peer user canceled handshake.") + +ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT , (SSL_ERROR_BASE + 102), +"Peer does not permit renegotiation of SSL security parameters.") + +ER3(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED , (SSL_ERROR_BASE + 103), +"SSL server cache not configured and not disabled for this socket.") + +ER3(SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT , (SSL_ERROR_BASE + 104), +"SSL peer does not support requested TLS hello extension.") + +ER3(SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT , (SSL_ERROR_BASE + 105), +"SSL peer could not obtain your certificate from the supplied URL.") + +ER3(SSL_ERROR_UNRECOGNIZED_NAME_ALERT , (SSL_ERROR_BASE + 106), +"SSL peer has no certificate for the requested DNS name.") + +ER3(SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT , (SSL_ERROR_BASE + 107), +"SSL peer was unable to get an OCSP response for its certificate.") + +ER3(SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT , (SSL_ERROR_BASE + 108), +"SSL peer reported bad certificate hash value.") diff --git a/mozilla/security/python/nss/src/__init__.py b/mozilla/security/python/nss/src/__init__.py new file mode 100644 index 00000000000..33760ca6ac7 --- /dev/null +++ b/mozilla/security/python/nss/src/__init__.py @@ -0,0 +1,298 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is a Python binding for Network Security Services (NSS). +# +# The Initial Developer of the Original Code is Red Hat, Inc. +# (Author: John Dennis ) +# +# Portions created by the Initial Developer are Copyright (C) 2008,2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +""" +============ +Introduction +============ + +This package provides a binding for the Network Security Services +(NSS) library. Because NSS directly uses the Netscape Portable Runtime +(NSPR) the binding also provides support for NSPR. There is an +inherent conflict between NSPR and Python, please see the Issues +section for more detail. + +General documentation on NSS can be found here: + +http://www.mozilla.org/projects/security/pki/nss + +General documentation on NSPR can be found here: + +http://developer.mozilla.org/en/docs/NSPR_API_Reference + +Please note, the documentation included with this package already +encapsultes most of the information at the above two URL's, but is +specific to the python binding of NSS/NSPR. It is suggested you refer +to the python-nss documentation. + +Most of the names and symbols in the NSS/NSPR C API have been kept in +the nss-python binding and should be instantly familar or +recognizable. Python has different naming conventions and the +nss-python binding has adhered to the python naming convensions, +Classes are camel case, otherwise symbols are all lower case with +words seperated by underscores. The constants used by NSS/NSPR in C +API have been imported literally to add the programmer who might be +referring to the Mozilla NSS/NSPR documentation and/or header files or +who is porting an existing C application to python. Minor other +changes have been made in the interest of being "Pythonic". + +=============== +Getting Started +=============== + +NSS stores it's certificates and private keys in a security database +unlike OpenSSL which references it's certificates and keys via file +pathnames. This means unless you already have an NSS Certificate +Database (CertDB) the first order of business will be to create +one. When a NSS application initializes itself it will need to specify +the path to the CertDB (see "Things All NSS programs must do"). + +The CertDB is created and manipulated by the command line utilities +certutil and modutil. Both of these programs are part of the nss-tools +RPM. Documentation for these tools can be found here: +http://www.mozilla.org/projects/security/pki/nss/tools + +Here is an example of creating a CertDB and populating it. In the +example the CertDB will be created under the directory "./pki", the CA +will be called "myca", the database password will be "myca", and the +server's hostname will be "myhost.example.com". + +1. Create the database:: + + certutil -N -d ./pki + + This creates a new database under the directory ./pki + +2. Create a root CA certificate:: + + certutil -d ./pki -S -s "CN=myca" -n myca -x -t "CTu,C,C" -m 1 + + This creates an individual certificate and adds it to the + certificate database with a subject of "CN=myca", a nickname of + "myca", trust flags indicating for SSL indicating it can issue + server certificates (C), can issue client certificates (T), and the + certificate can be used for authentication and signing (u). For + email and object signing it's trusted to create server + certificates. The certificate serial number is set to 1. + + +3. Create a server certificate and sign it. Our example server will + use this:: + + certutil -d pki -S -c myca -s "CN=myhost.example.com" -n myhost -t "C,C,C" -m 2 + + This creates an individual certificate issued by the CA "myca" and + adds it to the certificate database with a subject of + "CN=myhost.example.com", a nickname of "myhost". The certificate + serial number is set to 2. + +4. Import public root CA's:: + + modutil -add ca_certs -libfile /usr/lib/libnssckbi.so -dbdir ./pki + + This is necessary to verify certificates presented by a SSL server a + NSS client might connect to. When verifying a certificate the NSS + library will "walk the certificate chain" back to a root CA which + must be trusted. This command imports the well known root CA's as a + PKCS #11 module. + + +=============================== +Things All NSS programs must do +=============================== + +- Import the NSS/NSPR modules:: + + from nss.error import NSPRError + import nss.io as io + import nss.nss as nss + import nss.ssl as ssl + + In the interest of code brevity we drop the leading "nss." from the + module namespace. + +- Initialize NSS and indicate the certficate database (CertDB):: + + certdir = './pki' + ssl.nssinit(certdir) + +- If you are implementing an SSL server call config_secure_server() + (see ssl_example.py):: + + sock = ssl.SSLSocket() + sock.config_secure_server(server_cert, priv_key, server_cert_kea) + + **WARNING** you must call config_secure_server() for SSL servers, if + you do not call it the most likely result will be the NSS library + will segfault (not pretty). + +======== +Examples +======== + +There are example programs in under "examples" in the documentation +directory. On Fedora/RHEL/CentOS systems this will be +/usr/share/doc/python-nss. + +The ssl_example.py sample implements both a client and server in one +script. You tell it whether to run as a client (-C) or a server (-S) +when you invoke it. The sample shows many of the NSS/NSPR calls and +fully implements basic non-SSL client/server using NSPR, SSL +client/server using NSS, certificate validation, CertDB operations, +and client authentication using certificates. + +To get a list of command line options:: + + ssl_example.py --help + +Using the above example certificate database server can be run like +this:: + + ssl_example.py -S -c ./pki -n myhost + +The client can be run like this:: + + ssl_example.py -C -c ./pki + +====== +Issues +====== + +- The current partitioning of the NSS and NSPR API's into Python + modules (i.e. the Python namespaces and their symbols) is a first + cut and may not be ideal. One should be prepared for name changes as + the binding matures. + +- NSPR vs. Python + + An original design goal of NSS was to be portable, however NSS + required access to many system level functions which can vary + widely between platforms and OS's. Therefore NSPR was written to + encapsulate system services such as IO, sockets, threads, timers, + etc. into a common API to insulate NSS from the underlying + platform. + + In many respects Python and its collection of packages and modules + provides the same type of platform independence for applications + and libraries and provides it's own implementation of IO, sockets, + threads, timers, etc. + + Unfortunately NSPR's and Python's run time abstractions are not + the same nor can either be configured to use a different + underlying abstraction layer. + + Currently the NSS binding utilizes *only* the NSPR abstraction + layer. One consequence of this is it is not possible to create a + Python socket and use it as the foundation for any NSS functions + expecting a socket, or visa versa. + + You **must** use the nss.io module to create and manipulate a + socket used by NSS. You cannot pass this socket to any Python + library function expecting a socket. The two are not compatible. + + Here are some reasons for this incompatibility, perhaps in the + future we can find a solution but the immediate goal of the NSS + Python binding was to expose NSS through Python, not necessarily + to solve the larger integration issue of Python run-time and NSPR + run-time. + + - NSPR would like to hide the underlying platform socket (in the + NSPR code this is called "osfd"). There are NSPR API's which + will operate on osfd's + + - One can base a NSPR socket on an existing osfd via: + + - PR_ImportFile() + - PR_ImportPipe() + - PR_ImportTCPSocket() + - PR_ImportUDPSocket() + + - One can obtain the osfd in use by NSPR, either when the + osfd was imported or because NSPR created the osfd itself via: + + - PR_FileDesc2NativeHandle(); + + But note this function is not meant to be public in the NSPR + API and is documented as being deprecated and carries an + explicit warning against it's use. + + Once NSPR gets a hold of an osfd it manipulates it in a manner + as if it were the only owner of the osfd. Other native code + (e.g. the CPython socket code) which operates on the fd may run + afoul of NSPR belief it is the only code in the system operating + on the fd. For example in CPython the non-blocking flag is + directly set on the fd and non-blocking behavior is implemented + by the OS. However, NSPR manages non-blocking behavior + internally to the NSPR library eschewing direct OS support for + non-blocking. Thus CPython and NSPR are in direct conflict over + when and how non-blocking is set on an fd. Examples of this + problem can be seen in the Python socket.makefile() operation + which takes the fd belonging to a system socket, dups it, and + calls fdopen() on the dup'ed fd to return a FILE stream (all + Python file IO is based on file objects utilizing a FILE + stream). However, the dup'ed fd does not share the same + non-blocking flag, NSPR explicitly forces the flag off, Python + wants to directly manipulate it. Dup'ed fd's share their flags + thus if Python operates on the dup'ed fd returned by NSPR it's + going to confuse NSPR. Likewise if one sets non-blocking via + NSPR then Python won't honor the flag because Python is + expecting the flag to be set on the fd, not in some other + location (e.g. internal to NSPR). + + - Python's socket implementation is a very thin layer over the + Berkely socket API. There is very little abstraction, thus + Python and Python program expect to manipulate sockets directly + via their fd's. + + - The error and exception model for Python sockets and SSL is an + almost direct one-to-one mapping of the Posix and OpenSSL + errors. But NSS uses NSPR errors, thus Python code which has + exception handlers for sockets and SSL are expecting a complete + different set of exceptions. + + - Python's SSL implementation is a very thin layer over the + OpenSSL API, there is little abstraction. Thus there is a + sizeable body of Python code which expects the OpenSSL model for + IO ready and has exception handlers based on OpenSSL. + + +=== +FAQ +=== + +To be added + +""" diff --git a/mozilla/security/python/nss/src/py_nspr_common.h b/mozilla/security/python/nss/src/py_nspr_common.h new file mode 100644 index 00000000000..640749d99fc --- /dev/null +++ b/mozilla/security/python/nss/src/py_nspr_common.h @@ -0,0 +1,115 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +//#define DEBUG + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + +#define AddIntConstant(c) if (PyModule_AddIntConstant(m, #c, c) < 0) return; + +#ifdef DEBUG + +#define TraceMessage(_msg) \ +{ \ + printf("%s\n", _msg); \ +} + +#define TraceMethodEnter(_name, _obj) \ +{ \ + PyObject *repr = NULL; \ + char *repr_str = NULL; \ + \ + if (_obj) { \ + repr = _obj->ob_type->tp_repr((PyObject *)_obj); \ + repr_str = PyString_AsString(repr); \ + } \ + printf("%s: %s\n", _name, repr_str); \ + Py_XDECREF(repr); \ +} + +#define TraceMethodLeave(_name, _obj) \ +{ \ + PyObject *repr = NULL; \ + char *repr_str = NULL; \ + \ + if (_obj) { \ + repr = _obj->ob_type->tp_repr((PyObject *)_obj); \ + repr_str = PyString_AsString(repr); \ + } \ + printf("%s: %s\n", _name, repr_str); \ + Py_XDECREF(repr); \ +} + +#define TraceObjNewEnter(_name, _tp) \ +{ \ + PyTypeObject *tp = _tp; \ + if (tp != NULL) \ + printf("%s %s\n", _name, tp->tp_name); \ + else \ + printf("%s\n", _name); \ +} + + +#define TraceObjNewLeave(_name, _obj) \ +{ \ + PyObject *repr = NULL; \ + \ + if ((repr = _obj->ob_type->tp_repr((PyObject *)_obj))) { \ + printf("%s: returns %s\n", _name, PyString_AsString(repr)); \ + Py_DECREF(repr); \ + } \ +} + +#else +#define TraceMessage(_msg) +#define TraceMethodEnter(_name, _obj) +#define TraceMethodLeave(_name, _obj) +#define TraceObjNewEnter(_name, _tp) +#define TraceObjNewLeave(_name, _obj) +#endif diff --git a/mozilla/security/python/nss/src/py_nspr_error.c b/mozilla/security/python/nss/src/py_nspr_error.c new file mode 100644 index 00000000000..2b0a3a65a02 --- /dev/null +++ b/mozilla/security/python/nss/src/py_nspr_error.c @@ -0,0 +1,295 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "Python.h" +#include "structmember.h" + +#define NSPR_ERROR_MODULE +#include "py_nspr_error.h" + + +static PyObject *NSPR_Exception = NULL; + +typedef struct { + PRErrorCode num; + const char *name; + const char *string; +} NSPRErrorDesc; + +#include "nspr.h" +#include "seccomon.h" + +#define ER2(a,b) {a, #a, b}, +#define ER3(a,b,c) {a, #a, c}, + +#include "secerr.h" +#include "sslerr.h" + +NSPRErrorDesc nspr_errors[] = { +#include "SSLerrs.h" +#include "SECerrs.h" +#include "NSPRerrs.h" +}; + +static int +cmp_error(const void *p1, const void *p2) +{ + NSPRErrorDesc *e1 = (NSPRErrorDesc *) p1; + NSPRErrorDesc *e2 = (NSPRErrorDesc *) p2; + + if (e1->num < e2->num) return -1; + if (e1->num > e2->num) return 1; + return 0; +} + +const int nspr_error_count = sizeof(nspr_errors) / sizeof(NSPRErrorDesc); + +static PRStatus +init_nspr_errors(void) { + int low = 0; + int high = nspr_error_count - 1; + int i; + PRErrorCode err_num; + int result = SECSuccess; + + /* Make sure table is in ascending order. binary search depends on it. */ + + qsort((void*)nspr_errors, nspr_error_count, sizeof(NSPRErrorDesc), cmp_error); + + PRErrorCode last_num = ((PRInt32)0x80000000); + for (i = low; i <= high; ++i) { + err_num = nspr_errors[i].num; + if (err_num <= last_num) { + result = SECFailure; + fprintf(stderr, +"sequence error in error strings at item %d\n" +"error %d (%s)\n" +"should come after \n" +"error %d (%s)\n", + i, last_num, nspr_errors[i-1].string, + err_num, nspr_errors[i].string); + } + last_num = err_num; + } + return result; +} + +static const NSPRErrorDesc * +lookup_nspr_error(PRErrorCode num) { + int low = 0; + int high = nspr_error_count - 1; + int i; + PRErrorCode err_num; + + /* Do binary search of table. */ + while (low + 1 < high) { + i = (low + high) / 2; + err_num = nspr_errors[i].num; + if (num == err_num) + return &nspr_errors[i]; + if (num < err_num) + high = i; + else + low = i; + } + if (num == nspr_errors[low].num) + return &nspr_errors[low]; + if (num == nspr_errors[high].num) + return &nspr_errors[high]; + return NULL; +} + +static PyObject * +set_nspr_error(const char *format, ...) +{ + va_list vargs; + PyObject *v; + const NSPRErrorDesc *error_desc; + char *errstr=NULL; + PRErrorCode err; + PyObject *detail = NULL; + char buf[1024]; + + if (format) { +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + detail = PyString_FromFormatV(format, vargs); + va_end(vargs); + } + + err = PR_GetError(); + PR_GetErrorText(errstr); + if (errstr == NULL) { + if ((error_desc = lookup_nspr_error(err)) != NULL) { + snprintf(buf, sizeof(buf), "(%s) %s", error_desc->name, error_desc->string); + errstr = buf; + } else { + errstr = NULL; + } + + } + + if (detail) { + v = Py_BuildValue("(isS)", err, errstr, detail); + Py_DECREF(detail); + } else { + v = Py_BuildValue("(is)", err, errstr); + } + if (v != NULL) { + PyErr_SetObject(NSPR_Exception, v); + Py_DECREF(v); + } + return NULL; +} + +PyDoc_STRVAR(io_get_nspr_error_string_doc, +"get_nspr_error_string(number) -> string\n\ +\n\ +Given an NSPR error number, returns it's string description\n\ +"); + +static PyObject * +io_get_nspr_error_string(PyObject *self, PyObject *args) +{ + int err_num; + NSPRErrorDesc const *error_desc = NULL; + + if (!PyArg_ParseTuple(args, "i:get_nspr_error_string", &err_num)) { + return NULL; + } + + if ((error_desc = lookup_nspr_error(err_num)) == NULL) + Py_RETURN_NONE; + + return PyString_FromString(error_desc->string); +} + +/* List of functions exported by this module. */ +static PyMethodDef +module_methods[] = { + {"get_nspr_error_string", io_get_nspr_error_string, METH_VARARGS, io_get_nspr_error_string_doc}, + {NULL, NULL} /* Sentinel */ +}; + +static PyObject * +init_py_nspr_errors(PyObject *module) +{ + NSPRErrorDesc *error_desc = NULL; + PyObject *py_error_doc = NULL; + PyObject *error_str = NULL; + int i; + + /* Load and intialize NSPR error descriptions */ + if (init_nspr_errors() != PR_SUCCESS) + return NULL; + + /* Create a python string to hold the modules error documentation */ + if ((py_error_doc = PyString_FromString("NSPR Error Constants:\n\n")) == NULL) + return NULL; + + /* + * Iterate over all the NSPR errors, for each: + * add it's doc string to the module doc + * add it's numeric value as as a module constant + */ + for (i = 0, error_desc = &nspr_errors[0]; i < nspr_error_count; i++, error_desc++) { + + if ((error_str = PyString_FromFormat("%s: %s\n\n", error_desc->name, error_desc->string)) == NULL) { + Py_DECREF(py_error_doc); + return NULL; + } + PyString_ConcatAndDel(&py_error_doc, error_str); + + if (PyModule_AddIntConstant(module, error_desc->name, error_desc->num) < 0) { + Py_DECREF(py_error_doc); + return NULL; + } + } + return py_error_doc; +} + +/* ============================== Module Exports ============================= */ + +static PyNSPR_ERROR_C_API_Type nspr_error_c_api = +{ + NULL, /* nspr_exception */ + set_nspr_error, /* set_nspr_error */ +}; + +/* ============================== Module Construction ============================= */ + +PyDoc_STRVAR(module_doc, +"This module defines the NSPR errors and provides functions to\n\ +manipulate them.\n\ +"); + +PyMODINIT_FUNC +initerror(void) +{ + PyObject *m; + PyObject *py_error_doc = NULL; + PyObject *py_module_doc = NULL; + + if ((m = Py_InitModule3("error", module_methods, module_doc)) == NULL) + return; + + if ((py_error_doc = init_py_nspr_errors(m)) == NULL) + return; + + if ((py_module_doc = PyString_FromString(module_doc)) == NULL) + return; + + PyString_ConcatAndDel(&py_module_doc, py_error_doc); + Py_INCREF(py_module_doc); + PyModule_AddObject(m, "__doc__", py_module_doc); + + /* exceptions */ + if ((NSPR_Exception = PyErr_NewException("nss.error.NSPRError", PyExc_EnvironmentError, NULL)) == NULL) + return; + Py_INCREF(NSPR_Exception); + if (PyModule_AddObject(m, "NSPRError", NSPR_Exception) < 0) + return; + + /* Export C API */ + nspr_error_c_api.nspr_exception = NSPR_Exception; + if (PyModule_AddObject(m, "_C_API", PyCObject_FromVoidPtr((void *)&nspr_error_c_api, NULL)) != 0) + return; + +} diff --git a/mozilla/security/python/nss/src/py_nspr_error.h b/mozilla/security/python/nss/src/py_nspr_error.h new file mode 100644 index 00000000000..260da5a236c --- /dev/null +++ b/mozilla/security/python/nss/src/py_nspr_error.h @@ -0,0 +1,89 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* NSPR header files */ +#undef HAVE_LONG_LONG /* FIXME: both Python.h and nspr.h define HAVE_LONG_LONG */ +#include "nspr.h" +#include "prerror.h" + +typedef struct { + PyObject *nspr_exception; + PyObject *(*set_nspr_error)(const char *format, ...); +} PyNSPR_ERROR_C_API_Type; + +#ifdef NSPR_ERROR_MODULE + +#else /* not NSPR_ERROR_MODULE */ + +static PyNSPR_ERROR_C_API_Type nspr_error_c_api; + +#define set_nspr_error (*nspr_error_c_api.set_nspr_error) + +static int +import_nspr_error_c_api(void) +{ + PyObject *module = NULL; + PyObject *c_api_object = NULL; + void *api = NULL; + + if ((module = PyImport_ImportModule("nss.error")) == NULL) + return -1; + + if ((c_api_object = PyObject_GetAttrString(module, "_C_API")) == NULL) { + Py_DECREF(module); + return -1; + } + + if (!(PyCObject_Check(c_api_object))) { + Py_DECREF(c_api_object); + Py_DECREF(module); + return -1; + } + + if ((api = PyCObject_AsVoidPtr(c_api_object)) == NULL) { + Py_DECREF(c_api_object); + Py_DECREF(module); + return -1; + } + + memcpy(&nspr_error_c_api, api, sizeof(nspr_error_c_api)); + Py_DECREF(c_api_object); + Py_DECREF(module); + return 0; +} + +#endif /* NSPR_ERROR_MODULE */ diff --git a/mozilla/security/python/nss/src/py_nspr_io.c b/mozilla/security/python/nss/src/py_nspr_io.c new file mode 100644 index 00000000000..2f96ea17832 --- /dev/null +++ b/mozilla/security/python/nss/src/py_nspr_io.c @@ -0,0 +1,2900 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// FIXME: add detail to each set_nspr_error() +// FIXME: should nspr exception be derived from IOError? Note our detail is IOError's filename +// FIXME: add factory functions for TCPSocket, UDPSocket +// FIXME: change where class initializers appear in the file, should be first so class methods can use them +// or just add prototypes for everything (maybe better solution). + +#include "Python.h" +#include "structmember.h" + +#include "py_nspr_common.h" +#define NSPR_IO_MODULE +#include "py_nspr_io.h" +#include "py_nspr_error.h" + +static char *unset_string = ""; + +#define Py_RETURN_BOOL(condition) {if (condition) Py_RETURN_TRUE; else Py_RETURN_FALSE;} + +static PyTypeObject NetworkAddressType; +static PyTypeObject HostEntryType; +static PyTypeObject SocketType; + +static PyObject * +HostEntry_get_hostname(HostEntry *self, void *closure); + +/* ========================================================================== */ +/* ================================ Utilities =============================== */ +/* ========================================================================== */ + +#ifdef MS_WINDOWS + typedef SOCKET SOCKET_T; + #ifdef MS_WIN64 + #define SIZEOF_SOCKET_T 8 + #else + #define SIZEOF_SOCKET_T 4 + #endif +#else + typedef int SOCKET_T; + #define SIZEOF_SOCKET_T SIZEOF_INT +#endif + +PROsfd PR_FileDesc2NativeHandle(PRFileDesc *); + +#if defined(MS_WINDOWS) || defined(__BEOS__) +#define SOCKETCLOSE closesocket +#define NO_DUP /* Actually it exists on NT 3.5, but what the heck... */ +#endif + +#ifndef SOCKETCLOSE +#define SOCKETCLOSE close +#endif + +static const char* +pr_family_str(value) +{ + switch(value) { + case PR_AF_INET: return "PR_AF_INET"; + case PR_AF_INET6: return "PR_AF_INET6"; + case PR_AF_LOCAL: return "PR_AF_LOCAL"; + case PR_AF_UNSPEC: return "PR_AF_UNSPEC"; + default: return "unknown"; + } +} + +static const char* +pr_file_desc_type_str(value) +{ + switch(value) { + case PR_DESC_FILE: return "PR_DESC_FILE"; + case PR_DESC_SOCKET_TCP: return "PR_DESC_SOCKET_TCP"; + case PR_DESC_SOCKET_UDP: return "PR_DESC_SOCKET_UDP"; + case PR_DESC_LAYERED: return "PR_DESC_LAYERED"; + case PR_DESC_PIPE: return "PR_DESC_PIPE"; + default: return "unknown"; + } +} + +#if 0 +static const char* +pr_sock_option_str(value) +{ + switch(value) { + case PR_SockOpt_Nonblocking: return "PR_SockOpt_Nonblocking"; + case PR_SockOpt_Linger: return "PR_SockOpt_Linger"; + case PR_SockOpt_Reuseaddr: return "PR_SockOpt_Reuseaddr"; + case PR_SockOpt_Keepalive: return "PR_SockOpt_Keepalive"; + case PR_SockOpt_RecvBufferSize: return "PR_SockOpt_RecvBufferSize"; + case PR_SockOpt_SendBufferSize: return "PR_SockOpt_SendBufferSize"; + case PR_SockOpt_IpTimeToLive: return "PR_SockOpt_IpTimeToLive"; + case PR_SockOpt_IpTypeOfService: return "PR_SockOpt_IpTypeOfService"; + case PR_SockOpt_AddMember: return "PR_SockOpt_AddMember"; + case PR_SockOpt_DropMember: return "PR_SockOpt_DropMember"; + case PR_SockOpt_McastInterface: return "PR_SockOpt_McastInterface"; + case PR_SockOpt_McastTimeToLive: return "PR_SockOpt_McastTimeToLive"; + case PR_SockOpt_McastLoopback: return "PR_SockOpt_McastLoopback"; + case PR_SockOpt_NoDelay: return "PR_SockOpt_NoDelay"; + case PR_SockOpt_MaxSegment: return "PR_SockOpt_MaxSegment"; + case PR_SockOpt_Broadcast: return "PR_SockOpt_Broadcast"; + default: return "unknown"; + } +} +#endif + + +#if 0 +static const char* +pr_initialize_netaddr_str(value) +{ + switch(value) { + case PR_IpAddrNull: return "PR_IpAddrNull"; + case PR_IpAddrAny: return "PR_IpAddrAny"; + case PR_IpAddrLoopback: return "PR_IpAddrLoopback"; + default: return "unknown"; + } +} + +static const char* +pr_socket_shutdown_str(value) +{ + switch(value) { + case PR_SHUTDOWN_RCV: return "PR_SHUTDOWN_RCV"; + case PR_SHUTDOWN_SEND: return "PR_SHUTDOWN_SEND"; + case PR_SHUTDOWN_BOTH: return "PR_SHUTDOWN_BOTH"; + default: return "unknown"; + } +} + + +#endif + +/* ========================================================================== */ +/* =========================== NetworkAddress Class ========================= */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +NetworkAddress_get_hostentry(NetworkAddress *self, void *closure) +{ + if (self->py_hostentry == NULL) { + self->py_hostentry = (HostEntry *)HostEntry_new_from_prnetaddr(&self->addr); + } + return (PyObject *)self->py_hostentry; +} + +static PyObject * +NetworkAddress_get_hostname(NetworkAddress *self, void *closure) +{ + if (self->py_hostname) { + Py_INCREF(self->py_hostname); + return self->py_hostname; + } + if (self->py_hostentry == NULL) { + if ((self->py_hostentry = (HostEntry *)HostEntry_new_from_prnetaddr(&self->addr)) == NULL) + return NULL; + } + if ((self->py_hostname = HostEntry_get_hostname(self->py_hostentry, NULL)) == NULL) + return NULL; + + Py_INCREF(self->py_hostname); + return self->py_hostname; +} + +static PyObject * +NetworkAddress_get_port(NetworkAddress *self, void *closure) +{ + return PyInt_FromLong(PR_ntohs(self->addr.inet.port)); +} + +static int +NetworkAddress_set_port(NetworkAddress *self, PyObject *value, void *closure) +{ + int port; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the port attribute"); + return -1; + } + + if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, "The port attribute value must be an integer"); + return -1; + } + + port = PyInt_AsLong(value); + if (PR_InitializeNetAddr(PR_IpAddrNull, port, &self->addr) != PR_SUCCESS) { + set_nspr_error(NULL); + return -1; + } + + return 0; +} + +static PyGetSetDef +NetworkAddress_getseters[] = { + {"hostentry", (getter)NetworkAddress_get_hostentry, NULL, "HostEntry object representing this NetworkAddress", NULL}, + {"hostname", (getter)NetworkAddress_get_hostname, NULL, + "If a hostname was used to construct this NetworkAddress then return that name (e.g. NetworkAddress(hostname), else return the reverse lookup hostname (equivalent to self.hostentry.hostname)", NULL}, + {"port", (getter)NetworkAddress_get_port, (setter)NetworkAddress_set_port, "network address port", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef +NetworkAddress_members[] = { + {"family", T_INT, offsetof(NetworkAddress, addr.raw.family), 0, "network address family"}, + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +PyDoc_STRVAR(NetworkAddress_set_from_string_doc, +"set_from_string(addr)\n\ +\n\ +:Parameters:\n\ + addr : string\n\ + the address string to convert\n\ +\n\ +Reinitializes the NetworkAddress object given a string.\n\ +Identical to constructing nss.io.NetworkAddress() with a\n\ +string value (see constructor for documentation).\n\ +"); +static PyObject * +NetworkAddress_set_from_string(NetworkAddress *self, PyObject *args) +{ + PyObject *addr = NULL; + char *addr_str = NULL; + + if (!PyArg_ParseTuple(args, "O!:set_from_string", &PyString_Type, &addr)) + return NULL; + addr_str = PyString_AsString(addr); + + /* First try to parse as a dotted decimal, if that fails try a DNS lookup */ + if (PR_StringToNetAddr(addr_str, &self->addr) != PR_SUCCESS) { + /* Not an address string, try DNS */ + PRHostEnt entry; + char buffer[PR_NETDB_BUF_SIZE]; + + Py_INCREF(addr); + self->py_hostname = addr; + if (PR_GetHostByName(addr_str, buffer, sizeof(buffer), &entry) != PR_SUCCESS) { + return set_nspr_error("cannot resolve address (%s)", addr_str); + } + if (PR_EnumerateHostEnt(0, &entry, 0, &self->addr) < 0) { + return set_nspr_error(NULL); + } + } + Py_RETURN_NONE; +} + +static PyMethodDef +NetworkAddress_methods[] = { + {"set_from_string", (PyCFunction)NetworkAddress_set_from_string, METH_VARARGS, NetworkAddress_set_from_string_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +NetworkAddress_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + NetworkAddress *self = NULL; + + TraceObjNewEnter("NetworkAddress_new", type); + + if ((self = (NetworkAddress *)type->tp_alloc(type, 0)) == NULL) return NULL; + memset(&self->addr, 0, sizeof(self->addr)); + self->py_hostname = NULL; + self->py_hostentry = NULL; + + TraceObjNewLeave("NetworkAddress_new", self); + return (PyObject *)self; +} + +static PyObject * +NetworkAddress_new_from_prnetaddr(PRNetAddr *pr_netaddr) +{ + NetworkAddress *self = NULL; + + TraceObjNewEnter("NetworkAddress_new_from_prnetaddr", NULL); + + if ((self = (NetworkAddress *) NetworkAddressType.tp_new(&NetworkAddressType, NULL, NULL)) == NULL) + return NULL; + + self->addr = *pr_netaddr; + + TraceObjNewLeave("NetworkAddress_new_from_prnetaddr", self); + return (PyObject *) self; +} + +static void +NetworkAddress_dealloc(NetworkAddress* self) +{ + TraceMethodEnter("NetworkAddress_dealloc", self); + + Py_XDECREF(self->py_hostname); + Py_XDECREF(self->py_hostentry); + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(NetworkAddress_doc, +"NetworkAddress(addr, port=0)\n\ +\n\ +:Parameters:\n\ + addr : string or integer\n\ + may be an int or a string.\n\ + port : integer\n\ + port number\n\ +\n\ +If addr argument is a string it may be either a numeric address or a DNS host\n\ +name. First the addr string is tested to see if it can be parsed as a IPv4\n\ +Dotted Decimal Notation or IPv6 Hexadecimal Notation, Otherwise the addr string\n\ +is passed to PR_GetHostByName to resolve the name. If the name is resolved the\n\ +first host entry returned by PR_EnumerateHostEnt is used to initialize the\n\ +NetworkAddress. If you need more fine grained control over which address is\n\ +selected from the HostEntry then utilize HostEntry.get_network_addresses()\n\ +instead.\n\ +\n\ +If the addr argument is an integer it may be one of the following constants:\n\ +\n\ +PR_IpAddrNull\n\ + Do not set the IP address, only set the port.\n\ + NetworkAddress(PR_IpAddrNull, 123) is equivalent to NetworkAddress(port=123)\n\ +\n\ +PR_IpAddrAny\n\ + Assign logical PR_INADDR_ANY to IP address. This wildcard value is typically\n\ + used to establish a socket on which to listen for incoming connection requests.\n\ +\n\ +PR_IpAddrLoopback\n\ + Assign logical PR_INADDR_LOOPBACK. A client can use this value to connect to\n\ + itself without knowing the host's network address.\n\ +\n\ +The optional port argument sets the port number in the NetworkAddress object.\n\ +The port number may be modfied later by assigning to the port attribute.\n\ +\n\ +Example::\n\ + \n\ + netaddr = nss.io.NetworkAddress('www.python.org')\n\ + print '%s %s' % (netaddr, netaddr.hostname)\n\ + netaddr = nss.io.NetworkAddress('82.94.237.218')\n\ + print '%s %s' % (netaddr, netaddr.hostname)\n\ + \n\ + Output:\n\ + 82.94.237.218:0 www.python.org\n\ + 82.94.237.218:0 dinsdale.python.org\n\ +"); + +static int +NetworkAddress_init(NetworkAddress *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"addr", "port", NULL}; + PyObject *addr = NULL; + int port = 0; + int addr_int = PR_IpAddrNull; + char *addr_str = NULL; + + + TraceMethodEnter("NetworkAddress_init", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi", kwlist, &addr, &port)) + return -1; + + if (addr && !(PyInt_Check(addr) || PyString_Check(addr))) { + PyErr_SetString(PyExc_ValueError, "addr must be an int or a string"); + return -1; + } + + if (addr && PyInt_Check(addr)) { + addr_int = PyInt_AsLong(addr); + switch(addr_int) { + case PR_IpAddrNull: + case PR_IpAddrAny: + case PR_IpAddrLoopback: + break; + default: + PyErr_SetString(PyExc_ValueError, "addr is an int, must be PR_IpAddrNull, PR_IpAddrAny or PR_IpAddrLoopback"); + return -1; + } + } + + if (PR_InitializeNetAddr(addr_int, port, &self->addr) != PR_SUCCESS) { + set_nspr_error(NULL); + return -1; + } + + if (addr && PyString_Check(addr)) { + addr_str = PyString_AsString(addr); + + /* First try to parse as a dotted decimal, if that fails try a DNS lookup */ + if (PR_StringToNetAddr(addr_str, &self->addr) != PR_SUCCESS) { + /* Not an address string, try DNS */ + PRHostEnt entry; + char buffer[PR_NETDB_BUF_SIZE]; + + Py_INCREF(addr); + self->py_hostname = addr; + if (PR_GetHostByName(addr_str, buffer, sizeof(buffer), &entry) != PR_SUCCESS) { + set_nspr_error("cannot resolve address (%s)", addr_str); + return -1; + } + if (PR_EnumerateHostEnt(0, &entry, port, &self->addr) < 0) { + set_nspr_error(NULL); + return -1; + } + } + } + return 0; +} + +static PyObject * +NetworkAddress_str(NetworkAddress *self) +{ + char buf[1024]; + + if (self->addr.raw.family == PR_AF_UNSPEC) { + return PyString_FromString(unset_string); + } + + if (PR_NetAddrToString(&self->addr, buf, sizeof(buf)) != PR_SUCCESS) { + return set_nspr_error(NULL); + } + + switch(self->addr.raw.family) { + case PR_AF_INET: + return PyString_FromFormat("%s:%d", buf, PR_ntohs(self->addr.inet.port)); + case PR_AF_INET6: + return PyString_FromFormat("[%s]:%d", buf, PR_ntohs(self->addr.ipv6.port)); + default: + return PyString_FromString(buf); + } +} + +static PyTypeObject +NetworkAddressType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.io.NetworkAddress", /* tp_name */ + sizeof(NetworkAddress), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)NetworkAddress_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)NetworkAddress_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + NetworkAddress_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NetworkAddress_methods, /* tp_methods */ + NetworkAddress_members, /* tp_members */ + NetworkAddress_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)NetworkAddress_init, /* tp_init */ + 0, /* tp_alloc */ + NetworkAddress_new, /* tp_new */ +}; + +/* ========================================================================== */ +/* ============================= HostEntry Class ============================ */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +HostEntry_get_hostname(HostEntry *self, void *closure) +{ + return PyString_FromString(self->entry.h_name); +} + +static PyObject * +HostEntry_get_aliases(HostEntry *self, void *closure) +{ + int len, i; + PyObject *alias_tuple = NULL; + PyObject *alias = NULL; + + if (self->entry.h_aliases) + for (len = 0; self->entry.h_aliases[len]; len++); + else + len = 0; + + if ((alias_tuple = PyTuple_New(len)) == NULL) + return NULL; + + for (i = 0; i < len; i++) { + if ((alias = PyString_FromString(self->entry.h_aliases[i])) == NULL) { + Py_DECREF(alias_tuple); + return NULL; + } + PyTuple_SetItem(alias_tuple, i, alias); + } + + return alias_tuple; +} + +static PyGetSetDef +HostEntry_getseters[] = { + {"hostname", (getter)HostEntry_get_hostname, (setter)NULL, "official name of host", NULL}, + {"aliases", (getter)HostEntry_get_aliases, (setter)NULL, "tuple of aliases for host", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef +HostEntry_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +PyDoc_STRVAR(HostEntry_get_network_addresses_doc, +"get_network_addresses(port=0)\n\ +\n\ +Return a tuple of all possible network address associated with this\n\ +HostEntry. Each item in the returned tuple is a NetworkAddress object.\n\ +"); +static PyObject * +HostEntry_get_network_addresses(HostEntry *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"port", NULL}; + int len, i; + PyObject *addr_tuple = NULL; + PyObject *py_netaddr = NULL; + PRNetAddr pr_netaddr; + + int port = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:get_network_addresses", kwlist, &port)) + return NULL; + + if (self->entry.h_addr_list) + for (len = 0; self->entry.h_addr_list[len]; len++); + else + len = 0; + + if ((addr_tuple = PyTuple_New(len)) == NULL) + return NULL; + + for (i = 0; i < len; i++) { + if (PR_EnumerateHostEnt(i, &self->entry, port, &pr_netaddr) < 0) { + Py_DECREF(addr_tuple); + return set_nspr_error(NULL); + } + if ((py_netaddr = NetworkAddress_new_from_prnetaddr(&pr_netaddr)) == NULL) { + Py_DECREF(addr_tuple); + return NULL; + } + PyTuple_SetItem(addr_tuple, i, py_netaddr); + } + + return addr_tuple; +} + +PyDoc_STRVAR(HostEntry_get_network_address_doc, +"get_network_address(port=0)\n\ +\n\ +:Parameters:\n\ + port : integer\n\ + optional port value specifying the port to associate with the NetworkAddress.\n\ +\n\ +Returns the first network address associated with this HostEntry as a\n\ +NetworkAddress object. Equivalent to get_network_addresses()[0]. Note,\n\ +may return None if the HostEntry does not have address associated with\n\ +it.\n\ +"); +static PyObject * +HostEntry_get_network_address(HostEntry *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"port", NULL}; + NetworkAddress *netaddr = NULL; + int port = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:get_network_address", kwlist, &port)) + return NULL; + + if (!self->entry.h_addr_list) + Py_RETURN_NONE; + + if (!self->entry.h_addr_list[0]) + Py_RETURN_NONE; + + if ((netaddr = (NetworkAddress *) NetworkAddressType.tp_new(&NetworkAddressType, NULL, NULL)) == NULL) + return NULL; + + if (PR_EnumerateHostEnt(0, &self->entry, port, &netaddr->addr) < 0) { + Py_DECREF(netaddr); + return set_nspr_error(NULL); + } + + return (PyObject *)netaddr; +} + +static PyMethodDef +HostEntry_methods[] = { + {"get_network_addresses", (PyCFunction)HostEntry_get_network_addresses, METH_VARARGS|METH_KEYWORDS, HostEntry_get_network_addresses_doc}, + {"get_network_address", (PyCFunction)HostEntry_get_network_address, METH_VARARGS|METH_KEYWORDS, HostEntry_get_network_address_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +HostEntry_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + HostEntry *self = NULL; + + TraceObjNewEnter("HostEntry_new", type); + + if ((self = (HostEntry *)type->tp_alloc(type, 0)) == NULL) return NULL; + memset(&self->entry, 0, sizeof(self->entry)); + memset(&self->buffer, 0, sizeof(self->buffer)); + + TraceObjNewLeave("HostEntry_new", self); + return (PyObject *)self; +} + +static PyObject * +HostEntry_new_from_prnetaddr(PRNetAddr *pr_netaddr) +{ + HostEntry *self = NULL; + + TraceObjNewEnter("HostEntry_new_from_prnetaddr", NULL); + + if ((self = (HostEntry *) HostEntryType.tp_new(&HostEntryType, NULL, NULL)) == NULL) + return NULL; + + if ((PR_GetHostByAddr(pr_netaddr, self->buffer, sizeof(self->buffer), &self->entry)) != PR_SUCCESS) { + return set_nspr_error(NULL); + } + + TraceObjNewLeave("HostEntry_new_from_prnetaddr", self); + return (PyObject *) self; +} + +static void +HostEntry_dealloc(HostEntry* self) +{ + TraceMethodEnter("HostEntry_dealloc", self); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(HostEntry_doc, +"HostEntry(addr)\n\ +\n\ +:Parameters:\n\ + addr : string or NetworkAddr object\n\ + May be either a string or a NetworkAddr object.\n\ + - If addr is string it is equivalent to GetHostByName.\n\ + - If addr is a NetworkAddress object it is equivalent to GetHostByAddr.\n\ +\n\ +An object used to encapsulate network address information for a\n\ +specific host.\n\ +"); + +static int +HostEntry_init(HostEntry *self, PyObject *args) +{ + PyObject *addr = NULL; + + TraceMethodEnter("HostEntry_init", self); + + if (!PyArg_ParseTuple(args, "O", &addr)) + return -1; + + if (PyString_Check(addr)) { + if (PR_GetHostByName(PyString_AsString(addr), self->buffer, sizeof(self->buffer), &self->entry) != PR_SUCCESS) { + set_nspr_error(NULL); + return -1; + } + } + else if (PyNetworkAddress_Check(addr)) { + if (PR_GetHostByAddr(&((NetworkAddress *)addr)->addr, self->buffer, sizeof(self->buffer), &self->entry) != PR_SUCCESS) { + set_nspr_error(NULL); + return -1; + } + } + + return 0; +} + +static PyObject * +HostEntry_str(HostEntry *self) +{ + PyObject *addrs = NULL; + PyObject *addr_list = NULL; + PyObject *addr_iter = NULL; + PyObject *addr = NULL; + PyObject *str = NULL; + PyObject *aliases = NULL; + PyObject *args = NULL; + PyObject *text = NULL; + int i; + + addrs = PyObject_CallMethod((PyObject *)self, "get_network_addresses", NULL); + if ((addr_list = PyTuple_New(PyTuple_Size(addrs))) == NULL) { + goto exit; + } + + if ((addr_iter = PyObject_GetIter(addrs)) == NULL) { + goto exit; + } + + for (i = 0; (addr = PyIter_Next(addr_iter)); i++) { + if ((str = PyObject_Str(addr)) == NULL) { + Py_DECREF(addr); + goto exit; + } + if (PyTuple_SetItem(addr_list, i, str) == -1) { + Py_DECREF(str); + goto exit; + } + } + + if ((aliases = PyObject_GetAttrString((PyObject *)self, "aliases")) == NULL) { + goto exit; + } + + args = Py_BuildValue("(sSS)", self->entry.h_name ? self->entry.h_name : "None", + aliases, addr_list); + text = PyString_Format(PyString_FromString("name=%s aliases=%s addresses=%s"), args); + + + exit: + Py_XDECREF(addrs); + Py_XDECREF(addr_list); + Py_XDECREF(addr_iter); + Py_XDECREF(aliases); + Py_XDECREF(args); + return text; + +} + +static PyTypeObject +HostEntryType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.io.HostEntry", /* tp_name */ + sizeof(HostEntry), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)HostEntry_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)HostEntry_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + HostEntry_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + HostEntry_methods, /* tp_methods */ + HostEntry_members, /* tp_members */ + HostEntry_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)HostEntry_init, /* tp_init */ + 0, /* tp_alloc */ + HostEntry_new, /* tp_new */ +}; + +/* ========================================================================== */ +/* ============================== Socket Class ============================== */ +/* ========================================================================== */ + +static void +Socket_init_from_prfiledesc(Socket *self, PRFileDesc *pr_socket, int family) +{ + TraceMethodEnter("Socket_init_from_prfiledesc", self); + + self->pr_socket = pr_socket; + self->family = family; +} + + +static PyObject * +Socket_new_from_prfiledesc(PRFileDesc *pr_socket, int family) +{ + Socket *self = NULL; + + TraceObjNewEnter("Socket_new_from_prfiledesc", NULL); + + if ((self = (Socket *) SocketType.tp_new(&SocketType, NULL, NULL)) == NULL) + return NULL; + + Socket_init_from_prfiledesc(self, pr_socket, family); + + TraceObjNewLeave("Socket_new_from_prfiledesc", self); + return (PyObject *) self; +} + +/* ============================ Attribute Access ============================ */ + +static PyObject * +Socket_get_netaddr(Socket *self, void *closure) +{ + if (!self->py_netaddr) { + Py_RETURN_NONE; + } + Py_INCREF(self->py_netaddr); + return (PyObject *)self->py_netaddr; +} + +// FIXME: should we just store this in our struct? +static PyObject * +Socket_get_desc_type(Socket *self, void *closure) +{ + int desc_type; + + if (!self->pr_socket) { + PyErr_SetString(PyExc_ValueError, "socket not intialized"); + return NULL; + } + + desc_type = PR_GetDescType(self->pr_socket); + return PyInt_FromLong(desc_type); +} + +static PyGetSetDef +Socket_getseters[] = { + {"netaddr", (getter)Socket_get_netaddr, (setter)NULL, "NetworkAddress object bound to this socket", NULL}, + {"desc_type", (getter)Socket_get_desc_type, (setter)NULL, "socket description: PR_DESC_FILE, PR_DESC_SOCKET_TCP, PR_DESC_SOCKET_UDP, PR_DESC_LAYERED, PR_DESC_PIPE", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef +Socket_members[] = { + {"family", T_INT, offsetof(Socket, family), 0, "socket family: PR_AF_INET, PR_AF_INET6, PR_AF_LOCAL, PR_AF_UNSPEC"}, + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +PyDoc_STRVAR(Socket_set_socket_option_doc, +"set_socket_option(option, ...)\n\ +\n\ +The method signature varies depending on the option, see below:\n\ +\n\ +Set socket to non-blocking IO\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_Nonblocking, bool)\n\ +\n\ +Time to linger on close if data is present in socket send buffer. \n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_Linger, polarity, interval)\n\ +\n\ +Allow local address reuse\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_Reuseaddr, bool)\n\ +\n\ +Keep connections alive\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_Keepalive, bool)\n\ +\n\ +Allow IP multicast loopback\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_McastLoopback, bool)\n\ +\n\ +Disable Nagle algorithm. Don't delay send to coalesce packets. \n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_NoDelay, bool)\n\ +\n\ +Enable broadcast\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_Broadcast, bool)\n\ +\n\ +Receive buffer size. \n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_RecvBufferSize, size)\n\ +\n\ +Send buffer size. \n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_SendBufferSize, size)\n\ +\n\ +Maximum segment size\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_MaxSegment, size)\n\ +\n\ +IP Time to Live\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_IpTimeToLive, interval)\n\ +\n\ +IP type of service and precedence\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_IpTypeOfService, tos)\n\ +\n\ +Add an IP group membership\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_AddMember, mcaddr, ifaddr)\n\ +\n\ +- mcaddr is a NetworkAddress object representing the IP multicast address of group\n\ +- ifaddr is a NetworkAddress object representing the local IP address of the interface\n\ +\n\ +Drop an IP group membership\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_DropMember, mcaddr, ifaddr)\n\ +\n\ +- mcaddr is a NetworkAddress object representing the IP multicast address of group\n\ +- ifaddr is a NetworkAddress object representing the local IP address of the interface\n\ +\n\ +Multicast Time to Live\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_McastTimeToLive, interval)\n\ +\n\ +Multicast interface address\n\ + ::\n\ + \n\ + set_socket_option(PR_SockOpt_McastInterface, ifaddr)\n\ +\n\ +- ifaddr is a NetworkAddress object representing the multicast interface address\n\ +" +); +static PyObject * +Socket_set_socket_option(Socket *self, PyObject *args) +{ + PyObject *py_option = NULL; + int option; + int bool; + unsigned int uint; + NetworkAddress *mcaddr = NULL; + NetworkAddress *ifaddr = NULL; + PRSocketOptionData data; + + TraceMethodEnter("Socket_set_socket_option", self); + + if ((py_option = PyTuple_GetItem(args, 0)) == NULL) { + PyErr_SetString(PyExc_TypeError, "set_socket_option: missing option argument"); + return NULL; + } + + if (!PyInt_Check(py_option)) { + PyErr_SetString(PyExc_TypeError, "set_socket_option: option must be an int"); + return NULL; + } + + option = PyInt_AsLong(py_option); + data.option = option; + + switch(option) { + case PR_SockOpt_Nonblocking: + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + return NULL; + data.value.non_blocking = bool; + break; + case PR_SockOpt_Linger: + if (!PyArg_ParseTuple(args, "iiI:set_socket_option", &option, &bool, &uint)) + return NULL; + data.value.linger.polarity = bool; + data.value.linger.linger = uint; + break; + case PR_SockOpt_Reuseaddr: + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + return NULL; + data.value.reuse_addr = bool; + break; + case PR_SockOpt_Keepalive: + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + return NULL; + data.value.keep_alive = bool; + break; + case PR_SockOpt_RecvBufferSize: + if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) + return NULL; + data.value.recv_buffer_size = uint; + break; + case PR_SockOpt_SendBufferSize: + if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) + return NULL; + data.value.send_buffer_size = uint; + break; + case PR_SockOpt_IpTimeToLive: + if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) + return NULL; + data.value.ip_ttl = uint; + break; + case PR_SockOpt_IpTypeOfService: + if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) + return NULL; + data.value.tos = uint; + break; + case PR_SockOpt_AddMember: + if (!PyArg_ParseTuple(args, "iO!O!:set_socket_option", &option, + &NetworkAddressType, &mcaddr, + &NetworkAddressType, &ifaddr)) + return NULL; + data.value.add_member.mcaddr = mcaddr->addr; + data.value.add_member.ifaddr = ifaddr->addr; + break; + case PR_SockOpt_DropMember: + if (!PyArg_ParseTuple(args, "iO!O!:set_socket_option", &option, + &NetworkAddressType, &mcaddr, + &NetworkAddressType, &ifaddr)) + return NULL; + data.value.drop_member.mcaddr = mcaddr->addr; + data.value.drop_member.ifaddr = ifaddr->addr; + break; + case PR_SockOpt_McastInterface: + if (!PyArg_ParseTuple(args, "iO!:set_socket_option", &option, + &NetworkAddressType, &ifaddr)) + return NULL; + data.value.mcast_if = ifaddr->addr; + break; + case PR_SockOpt_McastTimeToLive: + if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) + return NULL; + data.value.mcast_ttl = uint; + break; + case PR_SockOpt_McastLoopback: + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + return NULL; + data.value.mcast_loopback = bool; + break; + case PR_SockOpt_NoDelay: + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + return NULL; + data.value.no_delay = bool; + break; + case PR_SockOpt_MaxSegment: + if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) + return NULL; + data.value.max_segment = uint; + break; + case PR_SockOpt_Broadcast: + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + return NULL; + data.value.broadcast = bool; + break; + default: + PyErr_SetString(PyExc_ValueError, "set_socket_option: unknown option"); + return NULL; + } + + if (PR_SetSocketOption(self->pr_socket, &data) != PR_SUCCESS) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Socket_get_socket_option_doc, +"get_socket_option(option)\n\ +\n\ +The method return values varies depending on the option, see below:\n\ +\n\ +Set socket to non-blocking IO\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_Nonblocking) -> bool\n\ +\n\ +Time to linger on close if data is present in socket send buffer. \n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_Linger) -> (polarity, interval)\n\ +\n\ +Allow local address reuse\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_Reuseaddr) -> bool\n\ +\n\ +Keep connections alive\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_Keepalive) -> bool\n\ +\n\ +Allow IP multicast loopback\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_McastLoopback) -> bool\n\ +\n\ +Disable Nagle algorithm. Don't delay send to coalesce packets. \n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_NoDelay) -> bool\n\ +\n\ +Enable broadcast\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_Broadcast) -> bool\n\ +\n\ +Receive buffer size. \n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_RecvBufferSize) -> size\n\ +\n\ +Send buffer size. \n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_SendBufferSize) -> size\n\ +\n\ +Maximum segment size\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_MaxSegment) -> size\n\ +\n\ +IP Time to Live\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_IpTimeToLive) -> interval\n\ +\n\ +IP type of service and precedence\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_IpTypeOfService) -> tos\n\ +\n\ +Add an IP group membership\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_AddMember) -> (mcaddr, ifaddr)\n\ +\n\ +- mcaddr is a NetworkAddress object representing the IP multicast address of group\n\ +- ifaddr is a NetworkAddress object representing the local IP address of the interface\n\ +\n\ +Drop an IP group membership\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_DropMember) -> (mcaddr, ifaddr)\n\ +\n\ +- mcaddr is a NetworkAddress object representing the IP multicast address of group\n\ +- ifaddr is a NetworkAddress object representing the local IP address of the interface\n\ +\n\ +Multicast Time to Live\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_McastTimeToLive) -> interval\n\ +\n\ +Multicast interface address\n\ + ::\n\ + \n\ + get_socket_option(PR_SockOpt_McastInterface) -> ifaddr\n\ +\n\ +- ifaddr is a NetworkAddress object representing the multicast interface address\n\ +" +); +static PyObject * +Socket_get_socket_option(Socket *self, PyObject *args) +{ + int option; + PyObject *mcaddr = NULL; + PyObject *ifaddr = NULL; + PRSocketOptionData data; + + TraceMethodEnter("Socket_get_socket_option", self); + + if (!PyArg_ParseTuple(args, "i:get_socket_option", &option)) + return NULL; + + data.option = option; + if (PR_GetSocketOption(self->pr_socket, &data) != PR_SUCCESS) + return set_nspr_error(NULL); + + switch(option) { + case PR_SockOpt_Nonblocking: + Py_RETURN_BOOL(data.value.non_blocking); + break; + case PR_SockOpt_Linger: + return Py_BuildValue("OI", data.value.linger.polarity ? Py_True : Py_False, data.value.linger.linger); + break; + case PR_SockOpt_Reuseaddr: + Py_RETURN_BOOL(data.value.reuse_addr); + break; + case PR_SockOpt_Keepalive: + Py_RETURN_BOOL(data.value.keep_alive); + break; + case PR_SockOpt_RecvBufferSize: + return Py_BuildValue("I", data.value.recv_buffer_size); + break; + case PR_SockOpt_SendBufferSize: + return Py_BuildValue("I", data.value.send_buffer_size); + break; + case PR_SockOpt_IpTimeToLive: + return Py_BuildValue("I", data.value.ip_ttl); + break; + case PR_SockOpt_IpTypeOfService: + return Py_BuildValue("I", data.value.tos); + break; + case PR_SockOpt_AddMember: + if ((mcaddr = NetworkAddress_new_from_prnetaddr(&data.value.add_member.mcaddr)) == NULL) { + return NULL; + } + if ((ifaddr = NetworkAddress_new_from_prnetaddr(&data.value.add_member.ifaddr)) == NULL) { + Py_DECREF(mcaddr); + return NULL; + } + return Py_BuildValue("OO", mcaddr, ifaddr); + break; + case PR_SockOpt_DropMember: + if ((mcaddr = NetworkAddress_new_from_prnetaddr(&data.value.drop_member.mcaddr)) == NULL) { + return NULL; + } + if ((ifaddr = NetworkAddress_new_from_prnetaddr(&data.value.drop_member.ifaddr)) == NULL) { + Py_DECREF(mcaddr); + return NULL; + } + return Py_BuildValue("OO", mcaddr, ifaddr); + break; + case PR_SockOpt_McastInterface: + if ((ifaddr = NetworkAddress_new_from_prnetaddr(&data.value.mcast_if)) == NULL) { + return NULL; + } + return ifaddr; + break; + case PR_SockOpt_McastTimeToLive: + return Py_BuildValue("I", data.value.mcast_ttl); + break; + case PR_SockOpt_McastLoopback: + Py_RETURN_BOOL(data.value.mcast_loopback); + break; + case PR_SockOpt_NoDelay: + Py_RETURN_BOOL(data.value.no_delay); + break; + case PR_SockOpt_MaxSegment: + return Py_BuildValue("I", data.value.max_segment); + break; + case PR_SockOpt_Broadcast: + Py_RETURN_BOOL(data.value.broadcast); + break; + default: + PyErr_SetString(PyExc_ValueError, "get_socket_option: unknown option"); + return NULL; + } + return NULL; +} + +PyDoc_STRVAR(Socket_connect_doc, +"connect(addr, timeout=PR_INTERVAL_NO_TIMEOUT)\n\ +\n\ +:Parameters:\n\ + addr : NetworkAddress object\n\ + address to connect to\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +Socket.connect() is usually invoked on a TCP socket, but it may also\n\ +be invoked on a UDP socket. Both cases are discussed here.\n\ +\n\ +If the socket is a TCP socket, Socket.connect() establishes a TCP\n\ +connection to the peer. If the socket is not bound, it will be bound\n\ +to an arbitrary local address.\n\ +\n\ +Socket.connect() blocks until either the connection is successfully\n\ +established or an error occurs. If the timeout parameter is not\n\ +PR_INTERVAL_NO_TIMEOUT and the connection setup cannot complete before\n\ +the time limit, Socket.connect() fails with the error code\n\ +PR_IO_TIMEOUT_ERROR.\n\ +\n\ +If the socket is a UDP socket, there is no connection setup to speak\n\ +of, since UDP is connectionless. If Socket.connect() is invoked on a\n\ +UDP socket, it has an overloaded meaning: Socket.connect() merely\n\ +saves the specified address as the default peer address for the\n\ +socket, so that subsequently one can send and receive datagrams from\n\ +the socket using Socket.send() and Socket.recv() instead of the usual\n\ +Socket.send_to() and Socket.recv_from().\n\ +"); + +static PyObject * +Socket_connect(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"addr", "timeout", NULL}; + NetworkAddress *py_netaddr = NULL; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + + TraceMethodEnter("Socket_connect", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|I:connect", kwlist, + &NetworkAddressType, &py_netaddr, &timeout)) + return NULL; + + Py_XDECREF(self->py_netaddr); + Py_INCREF(py_netaddr); + self->py_netaddr = py_netaddr; + + if (PR_Connect(self->pr_socket, &py_netaddr->addr, timeout) != PR_SUCCESS) { + Py_DECREF(self->py_netaddr); + self->py_netaddr = NULL; + return set_nspr_error(NULL); + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Socket_accept_doc, +"accept(timeout=PR_INTERVAL_NO_TIMEOUT) -> (Socket, NetworkAddress)\n\ +\n\ +:Parameters:\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +The socket is a rendezvous socket that has been bound to an address\n\ +with Socket.bind() and is listening for connections after a call to\n\ +Socket.listen(). Socket.accept() accepts the first connection from the\n\ +queue of pending connections and creates a new socket for the newly\n\ +accepted connection. The rendezvous socket can still be used to accept\n\ +more connections.\n\ +\n\ +Socket.accept() blocks the calling thread until either a new\n\ +connection is successfully accepted or an error occurs. If the timeout\n\ +parameter is not PR_INTERVAL_NO_TIMEOUT and no pending connection can\n\ +be accepted before the time limit, Socket.accept() raises a\n\ +nss.error.NSPRError exception with the error code PR_IO_TIMEOUT_ERROR.\n\ +\n\ +Socket.accept() returns a tuple containing a new Socket object and\n\ +Networkaddress object for the peer.\n\ +"); + +static PyObject * +Socket_accept(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"timeout", NULL}; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + PRNetAddr pr_netaddr; + PyObject *py_socket = NULL; + PyObject *py_netaddr = NULL; + PRFileDesc *pr_socket = NULL; + PyObject *return_values = NULL; + + TraceMethodEnter("Socket_accept", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|I:accept", kwlist, + &timeout)) + return NULL; + + if ((pr_socket = PR_Accept(self->pr_socket, &pr_netaddr, timeout)) == NULL) + return set_nspr_error(NULL); + + if ((py_netaddr = NetworkAddress_new_from_prnetaddr(&pr_netaddr)) == NULL) + goto error; + + if ((py_socket = Socket_new_from_prfiledesc(pr_socket, self->family)) == NULL) + goto error; + + if ((return_values = Py_BuildValue("OO", py_socket, py_netaddr)) == NULL) + goto error; + + return return_values; + + error: + Py_XDECREF(py_socket); + Py_XDECREF(py_netaddr); + Py_XDECREF(return_values); + return NULL; +} + +PyDoc_STRVAR(Socket_accept_read_doc, +"accept_read(amount, timeout=PR_INTERVAL_NO_TIMEOUT) -> (Socket, NetworkAddress, buf)\n\ +\n\ +:Parameters:\n\ + amount : integer\n\ + the maximum number of bytes to receive\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +Socket.accept_read() combines the behavior of Socket.accept() and\n\ +Socket.recv(). It accepts a new connection and after it performs an\n\ +initial read on the new socket as Socket.recv() would it returns the\n\ +newly created Socket and NetworkAddress objects for the peer as well\n\ +as a buffer of data.\n\ +\n\ +Socket.accept_read() returns a tuple containing a new Socket object, a\n\ +new Networkaddress object for the peer, and a bufer containing data\n\ +from the first read on the Socket object.\n\ +"); + +static PyObject * +Socket_accept_read(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"amount", "timeout", NULL}; + int requested_amount = 0; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + int amount_read; + PyObject *buf = NULL; + PRNetAddr *pr_netaddr; + PyObject *py_socket = NULL; + PyObject *py_netaddr = NULL; + PRFileDesc *pr_socket = NULL; + PyObject *return_values = NULL; + + /* FIXME: for consistency should use readahead buffering, but since this is the first read + * the readahead would be empty anyway */ + + TraceMethodEnter("Socket_accept_read", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|I:accept_read", kwlist, + &requested_amount, &timeout)) + return NULL; + + if ((buf = PyString_FromStringAndSize((char *) 0, requested_amount)) == NULL) + return NULL; + + if ((amount_read = PR_AcceptRead(self->pr_socket, &pr_socket, &pr_netaddr, + PyString_AS_STRING(buf), requested_amount, + timeout)) < 0) { + set_nspr_error(NULL); + goto error; + } + + if (amount_read != requested_amount) { + if (_PyString_Resize(&buf, amount_read) < 0) { + goto error; + } + } + + if ((py_netaddr = NetworkAddress_new_from_prnetaddr(pr_netaddr)) == NULL) + goto error; + + if ((py_socket = Socket_new_from_prfiledesc(pr_socket, self->family)) == NULL) + goto error; + + if ((return_values = Py_BuildValue("OOO", py_socket, py_netaddr, buf)) == NULL) + goto error; + + return return_values; + + error: + Py_XDECREF(buf); + Py_XDECREF(py_socket); + Py_XDECREF(py_netaddr); + Py_XDECREF(return_values); + return NULL; +} + +PyDoc_STRVAR(Socket_bind_doc, +"bind(addr)\n\ +\n\ +:Parameters:\n\ + addr : NetworkAddress object\n\ + address to bind to\n\ +\n\ +When a new socket is created, it has no address bound to\n\ +it. Socket.bind() assigns the specified network address to the\n\ +socket. If you do not care about the exact IP address assigned to the\n\ +socket, create a NetworkAddress object using PR_INADDR_ANY. If you do\n\ +not care about the TCP/UDP port assigned to the socket, set the port\n\ +value of the NetworkAddress object to 0.\n\ +\n\ +Note that if Socket.connect() is invoked on a socket that is not\n\ +bound, it implicitly binds an arbitrary address to the socket.\n\ +\n\ +Call Socket.get_sock_name to obtain the address (name) bound to a\n\ +socket.\n\ +"); + +static PyObject * +Socket_bind(Socket *self, PyObject *args) +{ + NetworkAddress *py_netaddr = NULL; + + TraceMethodEnter("Socket_bind", self); + + if (!PyArg_ParseTuple(args, "O!:bind", &NetworkAddressType, &py_netaddr)) + return NULL; + + Py_XDECREF(self->py_netaddr); + Py_INCREF(py_netaddr); + self->py_netaddr = py_netaddr; + + if (PR_Bind(self->pr_socket, &py_netaddr->addr) != PR_SUCCESS) { + Py_DECREF(self->py_netaddr); + self->py_netaddr = NULL; + return set_nspr_error(NULL); + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Socket_listen_doc, +"listen(backlog=5)\n\ +\n\ +:Parameters:\n\ + backlog : integer\n\ + The maximum length of the queue of pending connections.\n\ +\n\ +Socket.listen() turns the specified socket into a rendezvous\n\ +socket. It creates a queue for pending connections and starts to\n\ +listen for connection requests on the socket. The maximum size of the\n\ +queue for pending connections is specified by the backlog\n\ +parameter. Pending connections may be accepted by calling\n\ +Socket.accept().\n\ +"); + +static PyObject * +Socket_listen(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"backlog", NULL}; + int backlog = 5; + + TraceMethodEnter("Socket_listen", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|I:listen", kwlist, &backlog)) + return NULL; + + if (PR_Listen(self->pr_socket, backlog) != PR_SUCCESS) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Socket_shutdown_doc, +"shutdown(how=PR_SHUTDOWN_BOTH)\n\ +\n\ +:Parameters:\n\ + how : integer\n\ + The kind of disallowed operations on the socket.\n\ +\n\ + May be one of the following the following:\n\ + \n\ + PR_SHUTDOWN_RCV\n\ + Further receives will be disallowed.\n\ + PR_SHUTDOWN_SEND\n\ + Further sends will be disallowed.\n\ + PR_SHUTDOWN_BOTH\n\ + Further sends and receives will be disallowed. \n\ +"); + +static PyObject * +Socket_shutdown(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"how", NULL}; + int how = PR_SHUTDOWN_BOTH; + + TraceMethodEnter("Socket_shutdown", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|I:shutdown", kwlist, &how)) + return NULL; + + if (PR_Shutdown(self->pr_socket, how) != PR_SUCCESS) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Socket_close_doc, +"close()\n\ +\n\ +Close the socket.\n\ +"); + +static PyObject * +Socket_close(Socket *self, PyObject *args) +{ + TraceMethodEnter("Socket_close", self); + + if (PR_Close(self->pr_socket) != PR_SUCCESS) + return set_nspr_error(NULL); + + self->pr_socket = NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Socket_readline_doc, +"readline([size]) -> buf\n\ +\n\ +:Parameters:\n\ + size : integer\n\ + optional, read at most size bytes\n\ +\n\ +Read one entire line from the socket. If the size argument is present\n\ +and non-negative, it is a maximum byte count (including the trailing\n\ +newline) and an incomplete line may be returned. An empty string is\n\ +returned on EOF (connection close). Note: Unlike stdio's fgets(), the\n\ +returned string may contain null characters ('\0') if they occurred in\n\ +the input.\n\ +\n\ +The trailing line ending character(s) are preserved in the string (but\n\ +may be absent when a socket stream ends with an incomplete line). No\n\ +line ending conversions are performed. This is because some network\n\ +protocols require sequences in some parts of the protocol\n\ +stream but permit (e.g. newline) endings in encapsulated portions\n\ +of the protocol. It is up to the caller to make line endings canonical\n\ +or to strip them altogether if necessary for their application. Both\n\ +operations are trival and not considered a burden in light of the need\n\ +to read exact protocol sequences.\n\ +"); + +static PyObject * +Socket_readline(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"size", NULL}; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + long size = 0; + long read_len, space_available, amount_read, line_len; + PyObject *line = NULL; + + TraceMethodEnter("Socket_readline", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l:readline", kwlist, &size)) + return NULL; + + while (1) { + /* Is there a complete line already buffered */ + if (self->readahead.len) { + char *p, *beg, *end; + /* Set the beginning and ending pointers which defines the + * region inside of which a newline will be searched for. */ + beg = self->readahead.buf; + if (size > 0) { + end = beg + MIN(size, self->readahead.len); + } else { + end = beg + self->readahead.len; + } + /* Scan for a newline, stop at a newline or the limit of the scan, whichever comes first */ + for (p = beg; p < end && *p != '\n'; p++); + line_len = p - beg; + /* Where did we stop? + * At the size limit? Then return size bytes. + * At the end of the readahead buffer? No newline found, get more data. + * At a newline? Then return from the buffer begininning up to and including the newline */ + if ((size > 0) && (line_len == size)) goto return_line; + if (line_len == self->readahead.len) goto more_data; + assert(*p == '\n'); /* 1st two conditions don't apply, must have found newline */ + line_len++; /* always include line ending chars */ + goto return_line; + } + more_data: + /* Need more data, try to read at least an ALLOC_INCREMENT chunk */ + space_available = self->readahead.alloc_len - self->readahead.len; + if (space_available < ALLOC_INCREMENT) { + self->readahead.alloc_len = self->readahead.alloc_len + ALLOC_INCREMENT; + if ((self->readahead.buf = realloc(self->readahead.buf, self->readahead.alloc_len)) == NULL) { + /* ERROR */ + return NULL; + } + } + read_len = self->readahead.alloc_len - self->readahead.len; + if ((amount_read = PR_Recv(self->pr_socket, self->readahead.buf + self->readahead.len, read_len, 0, timeout)) < 0) { + return set_nspr_error(NULL); + } else if (amount_read == 0) { /* EOF, return what we've got */ + line_len = self->readahead.len; + goto return_line; + } + self->readahead.len += amount_read; + /* Got more data, go back and try again ... */ + } + assert(0); /* should never reach here */ + return_line: + if ((line = PyString_FromStringAndSize(self->readahead.buf, line_len)) == NULL) { + return NULL; + } + memmove(PyString_AsString(line), self->readahead.buf, line_len); + /* Subtract the data being returned from the cached readahead buffer */ + memmove(self->readahead.buf, self->readahead.buf + line_len, self->readahead.len - line_len); + self->readahead.len -= line_len; + return line; +} + +PyDoc_STRVAR(Socket_recv_doc, +"recv(amount, timeout=PR_INTERVAL_NO_TIMEOUT) -> buf\n\ +\n\ +:Parameters:\n\ + amount : integer\n\ + the maximum number of bytes to receive\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +Socket.recv() blocks until some positive number of bytes are\n\ +transferred, a timeout occurs, or an error occurs. No more than amount\n\ +bytes will be transferred.\n\ +\n\ +If the length of the returned buffer is 0 this indicates the network\n\ +connection is closed.\n\ +"); + +static PyObject * +Socket_recv(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"amount", "timeout", NULL}; + long requested_amount = 0; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + PyObject *buf = NULL; + long read_len, amount_read, result_len; + char *dst = NULL; + + TraceMethodEnter("Socket_recv", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|I:recv", kwlist, + &requested_amount, &timeout)) + return NULL; + + result_len = 0; + read_len = requested_amount; + if ((buf = PyString_FromStringAndSize(NULL, requested_amount)) == NULL) + return NULL; + + dst = PyString_AsString(buf); + + /* Is the read request already buffered? */ + if (self->readahead.len) { + if (self->readahead.len >= requested_amount) { + result_len = requested_amount; + memmove(dst, self->readahead.buf, result_len); + if (self->readahead.len > result_len) { + FREE_READAHEAD(&self->readahead); + } else { + memmove(self->readahead.buf, self->readahead.buf + result_len, self->readahead.len - result_len); + self->readahead.len -= result_len; + } + return buf; + } + + /* We'll completly empty the read ahead buffer satisfying this request so malloc + * the result string now, copy the read ahead portion into it and then free the + * read ahead. By eschewing the read ahead until it's needed again saves us an + * extra buffer copy on each subsequent read until it's needed again. */ + + memmove(dst, self->readahead.buf, self->readahead.len); + dst += self->readahead.len; + read_len = requested_amount - self->readahead.len; + FREE_READAHEAD(&self->readahead); + } + + /* Need more data */ + if ((amount_read = PR_Recv(self->pr_socket, dst, read_len, 0, timeout)) < 0) { + Py_DECREF(buf); + return set_nspr_error(NULL); + } + if (amount_read == 0) { + /* EOF */ + } + + result_len += amount_read; + + if (result_len != requested_amount) { + if (_PyString_Resize(&buf, result_len) < 0) { + Py_DECREF(buf); + return NULL; + } + } + return buf; +} + +PyDoc_STRVAR(Socket_read_doc, +"read(size=-1)\n\ +\n\ +:Parameters:\n\ + size : integer\n\ + If specified and non-negative the maximum number of bytes to receive\n\ + otherwise read till EOF\n\ +\n\ +If the length of the returned buffer is 0 this indicates the network\n\ +connection is closed.\n\ +"); + +static PyObject * +Socket_read(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"size", NULL}; + long requested_amount = -1; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + PyObject *buf = NULL; + long read_len, space_available, amount_read; + + TraceMethodEnter("Socket_read", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l:read", kwlist, &requested_amount)) + return NULL; + + + do { + read_len = ALLOC_INCREMENT; + space_available = self->readahead.alloc_len - self->readahead.len; + if (space_available < read_len) { + self->readahead.alloc_len = self->readahead.alloc_len + ALLOC_INCREMENT; + if ((self->readahead.buf = PyMem_REALLOC(self->readahead.buf, self->readahead.alloc_len)) == NULL) { + return PyErr_NoMemory(); + } + } + read_len = self->readahead.alloc_len - self->readahead.len; + if ((amount_read = PR_Recv(self->pr_socket, self->readahead.buf + self->readahead.len, read_len, 0, timeout)) < 0) { + return set_nspr_error(NULL); + } + self->readahead.len += amount_read; + + if (self->readahead.len > PY_SSIZE_T_MAX) { + PyErr_Format(PyExc_OverflowError, "have read %ld bytes, this is more than a Python string can hold", self->readahead.len); + return NULL; + } + + } while (amount_read != 0); + + if ((buf = PyString_FromStringAndSize(self->readahead.buf, self->readahead.len)) == NULL) + return NULL; + FREE_READAHEAD(&self->readahead); + return buf; +} + +PyDoc_STRVAR(Socket_recv_from_doc, +"recv_from(amount, addr, timeout=PR_INTERVAL_NO_TIMEOUT) -> buf\n\ +\n\ +:Parameters:\n\ + amount : integer\n\ + the maximum number of bytes to receive\n\ + addr : NetworkAddress object\n\ + a NetworkAddress object to receive from\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +Socket.recv_from() blocks until some positive number of bytes are\n\ +transferred, a timeout occurs, or an error occurs. No more than amount\n\ +bytes will be transferred.\n\ +\n\ +If the length of the returned buffer is 0 this indicates the network\n\ +connection is closed.\n\ +\n\ +Note: Socket.recv_from() is usually used with a UDP socket.\n\ +"); + +static PyObject * +Socket_recv_from(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"amount", "addr", "timeout", NULL}; + int requested_amount = 0; + NetworkAddress *py_netaddr = NULL; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + int amount_read; + PyObject *buf = NULL; + + /* FIXME: for consistency should use readahead buffering, but since this is the first read + * the readahead would be empty anyway */ + + TraceMethodEnter("Socket_recv_from", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "iO!|I:recv_from", kwlist, + &requested_amount, &NetworkAddressType, &py_netaddr, &timeout)) + return NULL; + + Py_XDECREF(self->py_netaddr); + Py_INCREF(py_netaddr); + self->py_netaddr = py_netaddr; + + if ((buf = PyString_FromStringAndSize((char *) 0, requested_amount)) == NULL) + return NULL; + + if ((amount_read = PR_RecvFrom(self->pr_socket, PyString_AS_STRING(buf), + requested_amount, 0, &py_netaddr->addr, timeout)) < 0) { + Py_DECREF(self->py_netaddr); + self->py_netaddr = NULL; + Py_DECREF(buf); + return set_nspr_error(NULL); + } + + if (amount_read != requested_amount) { + if (_PyString_Resize(&buf, amount_read) < 0) { + Py_DECREF(buf); + return NULL; + } + } + return buf; +} + +PyDoc_STRVAR(Socket_send_doc, +"send(buf, timeout=PR_INTERVAL_NO_TIMEOUT) -> amount\n\ +\n\ +:Parameters:\n\ + buf : buffer\n\ + a buffer of data to transmit\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +Socket.send() blocks until all bytes are sent (unless the socket is in\n\ +non-blocking mode), a timeout occurs, or an error occurs. In the case\n\ +of a timeout or an error then a nss.error.NSPRError will be raised.\n\ +\n\ +The function returns the number of bytes actually transmitted.\n\ +"); + +static PyObject * +Socket_send(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"buf", "timeout", NULL}; + char *buf = NULL; + int len = 0; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + int amount; + + TraceMethodEnter("Socket_send", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#|I:send", kwlist, + &buf, &len, &timeout)) + return NULL; + + if ((amount = PR_Send(self->pr_socket, buf, len, 0, timeout)) < 0) { + return set_nspr_error(NULL); + } + + return PyInt_FromLong(amount); +} + +PyDoc_STRVAR(Socket_send_to_doc, +"send_to(buf, addr, timeout=PR_INTERVAL_NO_TIMEOUT) -> amount\n\ +\n\ +:Parameters:\n\ + buf : buffer\n\ + a buffer of data to transmit\n\ + addr : NetworkAddress object\n\ + a NetworkAddress object to send to\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +Socket.send_to() blocks until all bytes are sent (unless the socket is in\n\ +non-blocking mode), a timeout occurs, or an error occurs. In the case\n\ +of a timeout or an error then a nss.error.NSPRError will be raised.\n\ +\n\ +The function returns the number of bytes actually transmitted.\n\ +\n\ +Note: Socket.send_to() is usually used with a UDP socket.\n\ +"); + +static PyObject * +Socket_send_to(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"buf", "addr", "timeout", NULL}; + char *buf = NULL; + int len = 0; + NetworkAddress *py_netaddr = NULL; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + int amount; + + TraceMethodEnter("Socket_send_to", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#O!|I:send_to", kwlist, + &buf, &len, &NetworkAddressType, &py_netaddr, &timeout)) + return NULL; + + Py_XDECREF(self->py_netaddr); + Py_INCREF(py_netaddr); + self->py_netaddr = py_netaddr; + + if ((amount = PR_SendTo(self->pr_socket, buf, len, 0, &py_netaddr->addr, timeout)) < 0) { + Py_DECREF(self->py_netaddr); + self->py_netaddr = NULL; + return set_nspr_error(NULL); + } + + return PyInt_FromLong(amount); +} + +PyDoc_STRVAR(Socket_get_sock_name_doc, +"get_sock_name() -> NetworkAddress\n\ +\n\ +Return the network address for this socket.\n\ +"); + +static PyObject * +Socket_get_sock_name(Socket *self, PyObject *args) +{ + PRNetAddr pr_netaddr; + PyObject *py_netaddr = NULL; + + if (PR_GetSockName(self->pr_socket, &pr_netaddr) != PR_SUCCESS) + return set_nspr_error(NULL); + if ((py_netaddr = NetworkAddress_new_from_prnetaddr(&pr_netaddr)) == NULL) + return NULL; + + return py_netaddr; +} + +PyDoc_STRVAR(Socket_get_peer_name_doc, +"get_peer_name() -> NetworkAddress\n\ +\n\ +Return the network address for the connected peer socket.\n\ +"); + +static PyObject * +Socket_get_peer_name(Socket *self, PyObject *args) +{ + PRNetAddr pr_netaddr; + PyObject *py_netaddr = NULL; + + if (PR_GetPeerName(self->pr_socket, &pr_netaddr) != PR_SUCCESS) + return set_nspr_error(NULL); + if ((py_netaddr = NetworkAddress_new_from_prnetaddr(&pr_netaddr)) == NULL) + return NULL; + + return py_netaddr; +} + +PyDoc_STRVAR(Socket_fileno_doc, +"fileno() -> integer\n\ +\n\ +Return the integer file descriptor of the socket.\n\ +"); + +static PyObject * +Socket_fileno(Socket *self) +{ + PROsfd sock_fd = -1; + + if ((sock_fd = PR_FileDesc2NativeHandle(self->pr_socket)) == -1) { + return set_nspr_error(NULL); + } + +#if SIZEOF_SOCKET_T <= SIZEOF_LONG + return PyInt_FromLong((long)sock_fd); +#else + return PyLong_FromLongLong((PY_LONG_LONG)sock_fd); +#endif +} + +#ifndef NO_DUP +/* s.makefile(mode) method. + Create a new open file object referring to a dupped version of + the socket's file descriptor. (The dup() call is necessary so + that the open file and socket objects may be closed independent + of each other.) + The mode argument specifies 'r' or 'w' passed to fdopen(). */ + +PyDoc_STRVAR(Socket_makefile_doc, +"makefile([mode[, buffersize]]) -> file object\n\ +\n\ +:Parameters:\n\ + mode : string\n\ + mode string identical to open(), e.g. 'r','w','rb', etc.\n\ + buffersize : integer\n\ + file buffer size\n\ +\n\ +Return a regular file object corresponding to the socket.\n\ +The mode and buffersize arguments are as for the built-in open() function."); + +static PyObject * +Socket_makefile(Socket *self, PyObject *args) +{ + extern int fclose(FILE *); + char *mode = "r"; + int bufsize = -1; + PROsfd sock_fd = -1; + +#ifdef MS_WIN32 + Py_intptr_t fd; +#else + int fd; +#endif + FILE *fp; + PyObject *f; + + if (!PyArg_ParseTuple(args, "|si:makefile", &mode, &bufsize)) + return NULL; + + if ((sock_fd = PR_FileDesc2NativeHandle(self->pr_socket)) == -1) { + return set_nspr_error(NULL); + } + +#ifdef MS_WIN32 + if (((fd = _open_osfhandle(sock_fd, _O_BINARY)) < 0) || + ((fd = dup(fd)) < 0) || ((fp = fdopen(fd, mode)) == NULL)) +#else + if ((fd = dup(sock_fd)) < 0 || (fp = fdopen(fd, mode)) == NULL) +#endif + { + if (fd >= 0) + SOCKETCLOSE(fd); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + if ((f = PyFile_FromFile(fp, "", mode, fclose)) != NULL) + PyFile_SetBufSize(f, bufsize); + + return f; +} + +#endif /* NO_DUP */ + +PyDoc_STRVAR(Socket_new_tcp_pair_doc, +"new_tcp_pair() -> (Socket, Socket)\n\ +\n\ +Returns a pair of connected TCP sockets: data written to one can be read from\n\ +the other and vice versa.\n\ +"); + +static PyObject * +Socket_new_tcp_pair(Socket *unused_class, PyObject *args) +{ + PRFileDesc *socks[2]; + PRNetAddr addr0, addr1; + PyObject *py_sock0 = NULL, *py_sock1 = NULL; + PyObject *return_value = NULL; + + TraceMethodEnter("Socket_new_tcp_pair", self); + + if (PR_NewTCPSocketPair(socks) != PR_SUCCESS) + return set_nspr_error(NULL); + + if (PR_GetSockName(socks[0], &addr0) != PR_SUCCESS + || PR_GetSockName(socks[1], &addr1) != PR_SUCCESS) { + return_value = set_nspr_error(NULL); + goto error_socks; + } + if ((py_sock0 = Socket_new_from_prfiledesc(socks[0], + PR_NetAddrFamily(&addr0))) + == NULL) + goto error_socks; + if ((py_sock1 = Socket_new_from_prfiledesc(socks[1], + PR_NetAddrFamily(&addr1))) + == NULL) + goto error_socks1; + if ((return_value = Py_BuildValue("OO", py_sock0, py_sock1)) == NULL) + goto error; + + return return_value; + + error_socks: + PR_Close(socks[0]); + error_socks1: + PR_Close(socks[1]); + error: + Py_XDECREF(py_sock0); + Py_XDECREF(py_sock1); + return return_value; +} + +PyDoc_STRVAR(Socket_poll_doc, +"poll(poll_descs, timeout) -> (flags, ...)\n\ +\n\ +:Parameters:\n\ + poll_descs : sequence of (Socket, flags) sequences\n\ + flags is a bitwise OR of PR_POLL_* flags\n\ + timeout : interval time\n\ + how long to block\n\ +\n\ +Wait until at least one of the Socket objects is ready for the action in\n\ +flags. Return a sequence of flags values, each representing the state of\n\ +the corresponding Socket in poll_descs.\n\ +"); + +static PyObject * +Socket_poll(Socket *unused_class, PyObject *args) +{ + PyObject *py_descs, *return_value = NULL, *py_desc = NULL, *o = NULL; + Py_ssize_t num_descs; + PRPollDesc *descs; + unsigned int timeout; + size_t i; + + if (!PyArg_ParseTuple(args, "OI:poll", &py_descs, &timeout)) + return NULL; + + if (!PySequence_Check(py_descs) + || (num_descs = PySequence_Size(py_descs)) == -1) { + PyErr_SetString(PyExc_TypeError, + "poll_descs is not a suitable sequence"); + return NULL; + } + + descs = PyMem_New(PRPollDesc, num_descs); + if (descs == NULL) + return PyErr_NoMemory(); + + for (i = 0; i < num_descs; i++) { + PyObject *py_desc, *o; + long flags; + + py_desc = PySequence_GetItem(py_descs, i); + if (py_desc == NULL) + goto err_descs_TypeError; + + o = PySequence_GetItem(py_desc, 0); + if (o == NULL) + goto err_descs; + if (!PyObject_TypeCheck(o, &SocketType)) + goto err_descs_TypeError; + descs[i].fd = ((Socket *)o)->pr_socket; + Py_CLEAR(o); + + o = PySequence_GetItem(py_desc, 1); + if (o == NULL) + goto err_descs; + flags = PyInt_AsLong(o); + if (flags == -1 && PyErr_Occurred()) + goto err_descs; + descs[i].in_flags = flags; + if (descs[i].in_flags != flags) /* Overflow */ + goto err_descs_TypeError; + + Py_CLEAR(py_desc); + } + if (PR_Poll(descs, num_descs, timeout) == -1) { + set_nspr_error(NULL); + goto err_descs; + } + + return_value = PyTuple_New(num_descs); + if (return_value == NULL) + goto err_descs; + for (i = 0; i < num_descs; i++) + PyTuple_SET_ITEM(return_value, i, PyInt_FromLong(descs[i].out_flags)); + + PyMem_Del(descs); + return return_value; + + err_descs_TypeError: + PyErr_SetString(PyExc_TypeError, "Invalid content of poll_descs"); + err_descs: + PyMem_Del(descs); + Py_XDECREF(py_desc); + Py_XDECREF(o); + Py_XDECREF(return_value); + return NULL; +} + +PyDoc_STRVAR(Socket_import_tcp_socket_doc, +"import_tcp_socket(osfd) -> Socket\n\ +:Parameters:\n\ + osfd : integer\n\ + file descriptor of the SOCK_STREAM socket to import\n\ +\n\ +Returns a Socket object that uses the specified socket file descriptor for\n\ +communication.\n\ +"); + +static PyObject * +Socket_import_tcp_socket(Socket *unused_class, PyObject *args) +{ + int osfd; + PRFileDesc *sock; + PRNetAddr addr; + PyObject *return_value = NULL; + + if (!PyArg_ParseTuple(args, "i:import_tcp_socket", &osfd)) + return NULL; + + sock = PR_ImportTCPSocket(osfd); + if (sock == NULL) + return set_nspr_error(NULL); + + if (PR_GetSockName(sock, &addr) != PR_SUCCESS) { + return_value = set_nspr_error(NULL); + goto error; + } + if ((return_value = Socket_new_from_prfiledesc(sock, + PR_NetAddrFamily(&addr))) + == NULL) + goto error; + + return return_value; + + error: + PR_Close(sock); + return NULL; +} + +static PyMethodDef +Socket_methods[] = { + {"set_socket_option", (PyCFunction)Socket_set_socket_option, METH_VARARGS, Socket_set_socket_option_doc}, + {"get_socket_option", (PyCFunction)Socket_get_socket_option, METH_VARARGS, Socket_get_socket_option_doc}, + {"connect", (PyCFunction)Socket_connect, METH_VARARGS|METH_KEYWORDS, Socket_connect_doc}, + {"accept", (PyCFunction)Socket_accept, METH_VARARGS|METH_KEYWORDS, Socket_accept_doc}, + {"accept_read", (PyCFunction)Socket_accept_read, METH_VARARGS|METH_KEYWORDS, Socket_accept_read_doc}, + {"bind", (PyCFunction)Socket_bind, METH_VARARGS, Socket_bind_doc}, + {"listen", (PyCFunction)Socket_listen, METH_VARARGS|METH_KEYWORDS, Socket_listen_doc}, + {"shutdown", (PyCFunction)Socket_shutdown, METH_VARARGS|METH_KEYWORDS, Socket_shutdown_doc}, + {"close" , (PyCFunction)Socket_close, METH_NOARGS, Socket_close_doc}, + {"recv", (PyCFunction)Socket_recv, METH_VARARGS|METH_KEYWORDS, Socket_recv_doc}, + {"read", (PyCFunction)Socket_read, METH_VARARGS|METH_KEYWORDS, Socket_read_doc}, + {"readline", (PyCFunction)Socket_readline, METH_VARARGS|METH_KEYWORDS, Socket_readline_doc}, + {"recv_from", (PyCFunction)Socket_recv_from, METH_VARARGS|METH_KEYWORDS, Socket_recv_from_doc}, + {"send", (PyCFunction)Socket_send, METH_VARARGS|METH_KEYWORDS, Socket_send_doc}, + {"send_to", (PyCFunction)Socket_send_to, METH_VARARGS|METH_KEYWORDS, Socket_send_to_doc}, + {"get_sock_name", (PyCFunction)Socket_get_sock_name, METH_NOARGS, Socket_get_sock_name_doc}, + {"get_peer_name", (PyCFunction)Socket_get_peer_name, METH_NOARGS, Socket_get_peer_name_doc}, + {"fileno", (PyCFunction)Socket_fileno, METH_NOARGS, Socket_fileno_doc}, +#ifndef NO_DUP + {"makefile", (PyCFunction)Socket_makefile, METH_VARARGS, Socket_makefile_doc}, +#endif + {"new_tcp_pair", (PyCFunction)Socket_new_tcp_pair, METH_NOARGS|METH_STATIC, Socket_new_tcp_pair_doc}, + {"poll" , (PyCFunction)Socket_poll, METH_VARARGS|METH_STATIC, Socket_poll_doc}, + {"import_tcp_socket", (PyCFunction)Socket_import_tcp_socket, METH_VARARGS|METH_STATIC, Socket_import_tcp_socket_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +Socket_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Socket *self; + + TraceObjNewEnter("Socket_new", type); + + if ((self = (Socket *)type->tp_alloc(type, 0)) == NULL) return NULL; + self->pr_socket = NULL; + self->family = 0; + self->py_netaddr = NULL; + INIT_READAHEAD(&self->readahead); + + TraceObjNewLeave("Socket_new", self); + return (PyObject *)self; +} + +static void +Socket_dealloc(Socket* self) +{ + TraceMethodEnter("Socket_dealloc", self); + + Py_XDECREF(self->py_netaddr); + FREE_READAHEAD(&self->readahead); + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(Socket_doc, +"Socket(family=PR_AF_INET, type=PR_DESC_SOCKET_TCP)\n\ +\n\ +:Parameters:\n\ + family : integer\n\ + one of:\n\ + - PR_AF_INET\n\ + - PR_AF_INET6\n\ + - PR_AF_LOCAL\n\ + type : integer\n\ + one of:\n\ + - PR_DESC_SOCKET_TCP\n\ + - PR_DESC_SOCKET_UDP\n\ +\n\ +Create a new NSPR socket:\n\ +\n\ +"); + +static int +Socket_init(Socket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"family", "type", NULL}; + int family = PR_AF_INET; + int desc_type = PR_DESC_SOCKET_TCP; + PRFileDesc *pr_socket = NULL; + + TraceMethodEnter("Socket_init", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist, + &family, &desc_type)) + return -1; + + /* If reinitializing, first close down previous socket */ + if (self->pr_socket) { + if (PR_Shutdown(self->pr_socket, PR_SHUTDOWN_BOTH) != PR_SUCCESS) { + /* ignore error */ + } + if (PR_Close(self->pr_socket) != PR_SUCCESS) { + /* ignore error */ + } + self->pr_socket = NULL; + } + + + switch (desc_type) { + case PR_DESC_SOCKET_TCP: + if ((pr_socket = PR_OpenTCPSocket(family)) == NULL) { + set_nspr_error(NULL); + return -1; + } + break; + case PR_DESC_SOCKET_UDP: + if ((pr_socket = PR_OpenUDPSocket(family)) == NULL) { + set_nspr_error(NULL); + return -1; + } + break; + default: + PyErr_SetString(PyExc_ValueError, "type must be PR_DESC_SOCKET_TCP or PR_DESC_SOCKET_UDP"); + return -1; + } + + + Socket_init_from_prfiledesc(self, pr_socket, family); + + return 0; +} + +static PyObject * +Socket_repr(Socket *self) +{ + return PyString_FromFormat("<%s object at %p PRFileDesc %p>", + self->ob_type->tp_name, self, self->pr_socket); +} + +static PyObject * +Socket_str(Socket *self) +{ + PyObject *args = NULL; + PyObject *text = NULL; + + args = Py_BuildValue("(ss)", + pr_family_str(self->family), + pr_file_desc_type_str(PR_GetDescType(self->pr_socket))); + if (!args) goto error; + text = PyString_Format(PyString_FromString("family=%s type=%s"), args); + + Py_DECREF(args); + return text; + + error: + Py_XDECREF(args); + Py_XDECREF(text); + return NULL; + +} + +static PyTypeObject +SocketType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.io.Socket", /* tp_name */ + sizeof(Socket), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Socket_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)Socket_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)Socket_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Socket_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Socket_methods, /* tp_methods */ + Socket_members, /* tp_members */ + Socket_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Socket_init, /* tp_init */ + 0, /* tp_alloc */ + Socket_new, /* tp_new */ +}; + +/* ========================================================================== */ +/* ================================= Module ================================= */ +/* ========================================================================== */ + +/* ============================== Module Methods ============================= */ + + +PyDoc_STRVAR(io_ntohs_doc, "16 bit conversion from network to host"); +static PyObject * +io_ntohs(PyObject *self, PyObject *args) +{ + int net, host; + + if (!PyArg_ParseTuple(args, "i:ntohs", &net)) { + return NULL; + } + host = PR_ntohs(net); + return PyInt_FromLong(host); +} + +PyDoc_STRVAR(io_ntohl_doc, "32 bit conversion from network to host"); +static PyObject * +io_ntohl(PyObject *self, PyObject *args) +{ + int net, host; + + if (!PyArg_ParseTuple(args, "i:ntohl", &net)) { + return NULL; + } + host = PR_ntohl(net); + return PyInt_FromLong(host); +} + +PyDoc_STRVAR(io_htons_doc, "16 bit conversion from host to network"); +static PyObject * +io_htons(PyObject *self, PyObject *args) +{ + int host, net ; + + if (!PyArg_ParseTuple(args, "i:htons", &host)) { + return NULL; + } + net = PR_htons(host); + return PyInt_FromLong(net); +} + +PyDoc_STRVAR(io_htonl_doc, "32 bit conversion from host to network"); +static PyObject * +io_htonl(PyObject *self, PyObject *args) +{ + int host, net ; + + if (!PyArg_ParseTuple(args, "i:htonl", &host)) { + return NULL; + } + net = PR_htonl(host); + return PyInt_FromLong(net); +} + +// FIXME: the PR_GetProto* functions return success even if they fail + +PyDoc_STRVAR(io_get_proto_by_name_doc, +"Returns the protocol number given the protocol's name. Raises exception if lookup fails."); +static PyObject * +io_get_proto_by_name(PyObject *self, PyObject *args) +{ + int rv; + char *name; + char buffer[PR_NETDB_BUF_SIZE]; /* this is where data pointed to in PRProtoEnt is stored */ + PRProtoEnt proto_ent; + + if (!PyArg_ParseTuple(args, "s:get_proto_by_name", &name)) { + return NULL; + } + + if ((rv = PR_GetProtoByName(name, buffer, sizeof(buffer), &proto_ent)) == PR_FAILURE) { + return set_nspr_error(NULL); + } + + return PyInt_FromLong(proto_ent.p_num); +} + + +PyDoc_STRVAR(io_get_proto_by_number_doc, +"Returns the protocol name and a tuple of aliases given the protocol's number.\n\ +name, aliases = get_proto_by_number(number)\n\ +Raises an exception if the lookup fails."); +static PyObject * +io_get_proto_by_number(PyObject *self, PyObject *args) +{ + int rv; + int number; + char buffer[PR_NETDB_BUF_SIZE]; /* this is where data pointed to in PRProtoEnt is stored */ + PRProtoEnt proto_ent; + int len, i; + PyObject *alias_tuple = NULL; + PyObject *alias = NULL; + PyObject *return_values; + + if (!PyArg_ParseTuple(args, "i:get_proto_by_number", &number)) { + return NULL; + } + + if ((rv = PR_GetProtoByNumber(number, buffer, sizeof(buffer), &proto_ent)) == PR_FAILURE) { + return set_nspr_error(NULL); + } + + for (len = 0; proto_ent.p_aliases[len]; len++); + + if ((alias_tuple = PyTuple_New(len)) == NULL) + return NULL; + + for (i = 0; i < len; i++) { + if ((alias = PyString_FromString(proto_ent.p_aliases[i])) == NULL) { + Py_DECREF(alias_tuple); + return NULL; + } + PyTuple_SetItem(alias_tuple, i, alias); + } + + if ((return_values = Py_BuildValue("sO", proto_ent.p_name, alias_tuple)) == NULL) + return NULL; + + Py_DECREF(alias_tuple); + + return return_values; +} + +PyDoc_STRVAR(io_interval_now_doc, +"You can use the value returned by interval_now() to establish epochs\n\ +and to determine intervals (that is, compute the difference\n\ +between two times)"); +static PyObject * +io_interval_now(PyObject *self, PyObject *args) +{ + PRIntervalTime interval; + + interval = PR_IntervalNow(); + return PyInt_FromLong(interval); +} + +PyDoc_STRVAR(io_ticks_per_second_doc, +"An integer between 1000 and 100000 indicating the number of ticks per\n\ +second counted by PRIntervalTime on the current platform.\n\ +\n\ +The value returned by ticks_per_second() lies between PR_INTERVAL_MIN\n\ +and PR_INTERVAL_MAX.\n\ + "); +static PyObject * +io_ticks_per_second(PyObject *self, PyObject *args) +{ + PRUint32 ticks_per_second; + + ticks_per_second = PR_TicksPerSecond(); + return PyInt_FromLong(ticks_per_second); +} + +PyDoc_STRVAR(io_seconds_to_interval_doc, +"Converts standard clock seconds to platform-dependent intervals."); +static PyObject * +io_seconds_to_interval(PyObject *self, PyObject *args) +{ + PRIntervalTime interval; + unsigned int seconds; + + if (!PyArg_ParseTuple(args, "I:seconds_to_interval", &seconds)) { + return NULL; + } + + interval = PR_SecondsToInterval(seconds); + return PyInt_FromLong(interval); +} + +PyDoc_STRVAR(io_milliseconds_to_interval_doc, +"Converts standard clock milliseconds to platform-dependent intervals."); +static PyObject * +io_milliseconds_to_interval(PyObject *self, PyObject *args) +{ + PRIntervalTime interval; + unsigned int milliseconds; + + if (!PyArg_ParseTuple(args, "I:milliseconds_to_interval", &milliseconds)) { + return NULL; + } + + interval = PR_MillisecondsToInterval(milliseconds); + return PyInt_FromLong(interval); +} + + +PyDoc_STRVAR(io_microseconds_to_interval_doc, +"Converts standard clock microseconds to platform-dependent intervals."); +static PyObject * +io_microseconds_to_interval(PyObject *self, PyObject *args) +{ + PRIntervalTime interval; + unsigned int microseconds; + + if (!PyArg_ParseTuple(args, "I:microseconds_to_interval", µseconds)) { + return NULL; + } + + interval = PR_MicrosecondsToInterval(microseconds); + return PyInt_FromLong(interval); +} + +PyDoc_STRVAR(io_interval_to_seconds_doc, +"Converts platform-dependent intervals to standard clock seconds"); +static PyObject * +io_interval_to_seconds(PyObject *self, PyObject *args) +{ + unsigned int interval; + unsigned int seconds; + + if (!PyArg_ParseTuple(args, "I:interval_to_seconds", &interval)) { + return NULL; + } + + seconds = PR_IntervalToSeconds(interval); + return PyInt_FromLong(seconds); +} + +PyDoc_STRVAR(io_interval_to_milliseconds_doc, +"Converts platform-dependent intervals to standard clock milliseconds"); +static PyObject * +io_interval_to_milliseconds(PyObject *self, PyObject *args) +{ + unsigned int interval; + unsigned int milliseconds; + + if (!PyArg_ParseTuple(args, "I:interval_to_milliseconds", &interval)) { + return NULL; + } + + milliseconds = PR_IntervalToMilliseconds(interval); + return PyInt_FromLong(milliseconds); +} + +PyDoc_STRVAR(io_interval_to_microseconds_doc, +"Converts platform-dependent intervals to standard clock microseconds"); +static PyObject * +io_interval_to_microseconds(PyObject *self, PyObject *args) +{ + unsigned int interval; + unsigned int microseconds; + + if (!PyArg_ParseTuple(args, "I:interval_to_microseconds", &interval)) { + return NULL; + } + + microseconds = PR_IntervalToMicroseconds(interval); + return PyInt_FromLong(microseconds); +} + +/* List of functions exported by this module. */ +static PyMethodDef +module_methods[] = { + {"ntohs", io_ntohs, METH_VARARGS, io_ntohs_doc}, + {"ntohl", io_ntohl, METH_VARARGS, io_ntohl_doc}, + {"htons", io_htons, METH_VARARGS, io_htons_doc}, + {"htonl", io_htonl, METH_VARARGS, io_htonl_doc}, + {"get_proto_by_name", io_get_proto_by_name, METH_VARARGS, io_get_proto_by_name_doc}, + {"get_proto_by_number", io_get_proto_by_number, METH_VARARGS, io_get_proto_by_number_doc}, + {"interval_now", io_interval_now, METH_NOARGS, io_interval_now_doc}, + {"ticks_per_second", io_ticks_per_second, METH_NOARGS, io_ticks_per_second_doc}, + {"seconds_to_interval", io_seconds_to_interval, METH_VARARGS, io_seconds_to_interval_doc}, + {"milliseconds_to_interval", io_milliseconds_to_interval, METH_VARARGS, io_milliseconds_to_interval_doc}, + {"microseconds_to_interval", io_microseconds_to_interval, METH_VARARGS, io_microseconds_to_interval_doc}, + {"interval_to_seconds", io_interval_to_seconds, METH_VARARGS, io_interval_to_seconds_doc}, + {"interval_to_milliseconds", io_interval_to_milliseconds, METH_VARARGS, io_interval_to_milliseconds_doc}, + {"interval_to_microseconds", io_interval_to_microseconds, METH_VARARGS, io_interval_to_microseconds_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* ============================== Module Exports ============================= */ + +static PyNSPR_IO_C_API_Type nspr_io_c_api = +{ + &NetworkAddressType, /* network_address_type */ + &HostEntryType, /* host_entry_type */ + &SocketType, /* socket_type */ + Socket_init_from_prfiledesc /* Socket_init_from_prfiledesc */ +}; + +/* ============================== Module Construction ============================= */ + +PyDoc_STRVAR(module_doc, +"This module implements the NSPR IO functions\n\ +\n\ +"); + +PyMODINIT_FUNC +initio(void) +{ + PyObject *m; + + if (import_nspr_error_c_api() < 0) + return; + + if (PyType_Ready(&NetworkAddressType) < 0) + return; + + if (PyType_Ready(&HostEntryType) < 0) + return; + + if (PyType_Ready(&SocketType) < 0) + return; + + if ((m = Py_InitModule3("io", module_methods, module_doc)) == NULL) + return; + + Py_INCREF(&NetworkAddressType); + PyModule_AddObject(m, "NetworkAddress", (PyObject *)&NetworkAddressType); + + Py_INCREF(&HostEntryType); + PyModule_AddObject(m, "HostEntry", (PyObject *)&HostEntryType); + + Py_INCREF(&SocketType); + PyModule_AddObject(m, "Socket", (PyObject *)&SocketType); + + /* Export C API */ + if (PyModule_AddObject(m, "_C_API", PyCObject_FromVoidPtr((void *)&nspr_io_c_api, NULL)) != 0) + return; + + /* Socket types */ + AddIntConstant(PR_AF_INET); + AddIntConstant(PR_AF_INET6); + AddIntConstant(PR_AF_LOCAL); + AddIntConstant(PR_AF_UNSPEC); + + /* PR_InitializeNetAddr */ + AddIntConstant(PR_IpAddrNull); + AddIntConstant(PR_IpAddrAny); + AddIntConstant(PR_IpAddrLoopback); + + /* PR_Shutdown */ + AddIntConstant(PR_SHUTDOWN_RCV); + AddIntConstant(PR_SHUTDOWN_SEND); + AddIntConstant(PR_SHUTDOWN_BOTH); + + + /* PRDescType */ + AddIntConstant(PR_DESC_FILE); + AddIntConstant(PR_DESC_SOCKET_TCP); + AddIntConstant(PR_DESC_SOCKET_UDP); + AddIntConstant(PR_DESC_LAYERED); + AddIntConstant(PR_DESC_PIPE); + + /* PRSockOption */ + AddIntConstant(PR_SockOpt_Nonblocking); + AddIntConstant(PR_SockOpt_Linger); + AddIntConstant(PR_SockOpt_Reuseaddr); + AddIntConstant(PR_SockOpt_Keepalive); + AddIntConstant(PR_SockOpt_RecvBufferSize); + AddIntConstant(PR_SockOpt_SendBufferSize); + AddIntConstant(PR_SockOpt_IpTimeToLive); + AddIntConstant(PR_SockOpt_IpTypeOfService); + AddIntConstant(PR_SockOpt_AddMember); + AddIntConstant(PR_SockOpt_DropMember); + AddIntConstant(PR_SockOpt_McastInterface); + AddIntConstant(PR_SockOpt_McastTimeToLive); + AddIntConstant(PR_SockOpt_McastLoopback); + AddIntConstant(PR_SockOpt_NoDelay); + AddIntConstant(PR_SockOpt_MaxSegment); + AddIntConstant(PR_SockOpt_Broadcast); + + /* Interval */ + AddIntConstant(PR_INTERVAL_MIN); + AddIntConstant(PR_INTERVAL_MAX); + AddIntConstant(PR_INTERVAL_NO_WAIT); + AddIntConstant(PR_INTERVAL_NO_TIMEOUT); + + /* Interval */ + AddIntConstant(PR_POLL_READ); + AddIntConstant(PR_POLL_WRITE); + AddIntConstant(PR_POLL_EXCEPT); + AddIntConstant(PR_POLL_ERR); + AddIntConstant(PR_POLL_NVAL); + AddIntConstant(PR_POLL_HUP); + +} diff --git a/mozilla/security/python/nss/src/py_nspr_io.h b/mozilla/security/python/nss/src/py_nspr_io.h new file mode 100644 index 00000000000..c85233110b1 --- /dev/null +++ b/mozilla/security/python/nss/src/py_nspr_io.h @@ -0,0 +1,164 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* NSPR header files */ +#undef HAVE_LONG_LONG /* FIXME: both Python.h and nspr.h define HAVE_LONG_LONG */ +#include "nspr.h" +#include "private/pprio.h" +#include "prnetdb.h" + +/* ========================================================================== */ +/* ============================= HostEntry Class ============================ */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PRHostEnt entry; + char buffer[PR_NETDB_BUF_SIZE]; /* this is where data pointed to in PRHostEnt is stored */ +} HostEntry; + +#define PyHostEntry_Check(op) PyObject_TypeCheck(op, &HostEntryType) + +/* ========================================================================== */ +/* =========================== NetworkAddress Class ========================= */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PRNetAddr addr; + PyObject *py_hostname; + HostEntry *py_hostentry; +} NetworkAddress; + +#define PyNetworkAddress_Check(op) PyObject_TypeCheck(op, &NetworkAddressType) + +/* ========================================================================== */ +/* ============================== Socket Class ============================== */ +/* ========================================================================== */ + +#define ALLOC_INCREMENT 128 +typedef struct { + char *buf; + long len; + long alloc_len; +} ReadAhead; + + +#define INIT_READAHEAD(readahead) \ +{ \ + (readahead)->buf = NULL; \ + (readahead)->len = 0; \ + (readahead)->alloc_len = 0; \ +} + +#define FREE_READAHEAD(readahead) \ +{ \ + if ((readahead)->buf) \ + PyMem_FREE((readahead)->buf); \ + INIT_READAHEAD(readahead); \ +} + +#define SOCKET_HEAD \ + PyObject_HEAD; \ + PRFileDesc *pr_socket; \ + int family; \ + NetworkAddress *py_netaddr; \ + ReadAhead readahead; + + +typedef struct { + SOCKET_HEAD +} Socket; + +#define PySocket_Check(op) PyObject_TypeCheck(op, &SocketType) + +typedef struct { + PyTypeObject *network_address_type; + PyTypeObject *host_entry_type; + PyTypeObject *socket_type; + void (*Socket_init_from_prfiledesc)(Socket *py_socket, PRFileDesc *pr_socket, int family); +} PyNSPR_IO_C_API_Type; + +#ifdef NSPR_IO_MODULE + +static PyObject * +HostEntry_new_from_prnetaddr(PRNetAddr *pr_netaddr); + +#else /* not NSPR_IO_MODULE */ + +static PyNSPR_IO_C_API_Type nspr_io_c_api; + +#define NetworkAddressType (*nspr_io_c_api.network_address_type) +#define HostEntryType (*nspr_io_c_api.host_entry_type) +#define SocketType (*nspr_io_c_api.socket_type) + +#define Socket_init_from_prfiledesc (*nspr_io_c_api.Socket_init_from_prfiledesc) + +static int +import_nspr_io_c_api(void) +{ + PyObject *module = NULL; + PyObject *c_api_object = NULL; + void *api = NULL; + + if ((module = PyImport_ImportModule("nss.io")) == NULL) + return -1; + + if ((c_api_object = PyObject_GetAttrString(module, "_C_API")) == NULL) { + Py_DECREF(module); + return -1; + } + + if (!(PyCObject_Check(c_api_object))) { + Py_DECREF(c_api_object); + Py_DECREF(module); + return -1; + } + + if ((api = PyCObject_AsVoidPtr(c_api_object)) == NULL) { + Py_DECREF(c_api_object); + Py_DECREF(module); + return -1; + } + + memcpy(&nspr_io_c_api, api, sizeof(nspr_io_c_api)); + Py_DECREF(c_api_object); + Py_DECREF(module); + return 0; +} + +#endif /* NSPR_IO_MODULE */ diff --git a/mozilla/security/python/nss/src/py_nss.c b/mozilla/security/python/nss/src/py_nss.c new file mode 100644 index 00000000000..0c33fd800cc --- /dev/null +++ b/mozilla/security/python/nss/src/py_nss.c @@ -0,0 +1,4803 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// FIXME: change all Python _from_ NSS function names to use the NSS typedef for clarity +// e.g. PrivateKey_new_from_private_key should be PrivateKey_new_from_SECKEYPrivateKey +// FIXME: should we be calling these? +// SECKEY_DestroyEncryptedPrivateKeyInfo +// SECKEY_DestroyPrivateKey SECKEY_DestroyPrivateKeyInfo +// SECKEY_DestroyPrivateKeyList SECKEY_DestroyPublicKey +// SECKEY_DestroyPublicKeyList SECKEY_DestroySubjectPublicKeyInfo + +#include "Python.h" +#include "structmember.h" + +#include "py_nspr_common.h" +#define NSPR_NSS_MODULE +#include "py_nss.h" +#include "py_nspr_error.h" + +#include "secder.h" +#include "certdb.h" +#include "hasht.h" + +#define OCTETS_PER_LINE_DEFAULT 16 +#define HEX_SEPARATOR_DEFAULT ":" + +#define FMT_OBJ_AND_APPEND(level, label, obj, lines, fail) \ +{ \ + PyObject *pair = NULL; \ + \ + Py_INCREF(obj); \ + if ((pair = fmt_pair(level, label, obj)) == NULL) goto fail; \ + Py_DECREF(obj); \ + if (PyList_Append(lines, pair) != 0) goto fail; \ +} + + +#define FMT_LABEL_AND_APPEND(level, label, lines, fail) \ +{ \ + PyObject *pair = NULL; \ + \ + if ((pair = fmt_label(level, label)) == NULL) goto fail; \ + if (PyList_Append(lines, pair) != 0) goto fail; \ +} + + +static char time_format[] = "%a %b %d %H:%M:%S %Y UTC"; +static char hex_chars[] = "0123456789abcdef"; +static PyObject *empty_tuple = NULL; + +typedef PyObject *(*format_lines_func)(PyObject *self, PyObject *args, PyObject *kwds); + +/* === Prototypes === */ + +static PyObject * +obj_to_hex(PyObject *obj, int octets_per_line, char *separator); + +static PyObject * +raw_data_to_hex(unsigned char *data, int data_len, int octets_per_line, char *separator); + +static SECStatus +sec_strip_tag_and_length(SECItem *item); + +static PyObject * +sec_context_specific_str(SECItem *item); + +static PyObject * +sec_any_str(SECItem *item); + +static PyObject * +sec_set_str_list(SECItem *item); + +static PyObject * +sec_boolean_str(SECItem *item); + +static PyObject * +sec_encoded_boolean_str(SECItem *item); + +static PyObject * +sec_integer_str(SECItem *item); + +static PyObject * +sec_encoded_integer_str(SECItem *item); + +static PyObject * +sec_string_str(SECItem *item); + +static PyObject * +sec_oid_str(SECItem *oid); + +static PyObject * +sec_encoded_oid_str(SECItem *item); + +static PyObject * +sec_utc_time_str(SECItem *item); + +static PyObject * +sec_generalized_time_str(SECItem *item); + +PRTime +sec_time_choice(SECItem *item); + +static PyObject * +sec_time_choice_str(SECItem *item); + +static PyObject * +sec_octet_str(SECItem *item); + +static PyObject * +sec_bit_str(SECItem *item); + +static PyObject * +sec_bmp_str(SECItem *item); + +static PyObject * +sec_universal_str(SECItem *item); + +static PyObject * +sec_universal_item_str(SECItem *item); + +static PyObject * +get_algorithm_id_str(SECAlgorithmID *a); + +static PyObject * +cert_trust_flags_str(unsigned int flags); + +static PyObject * +nss_indented_format(PyObject *self, PyObject *args, PyObject *kwds); + +static PyObject * +cert_md5_digest(PyObject *self, PyObject *args); + +static PyObject * +cert_sha1_digest(PyObject *self, PyObject *args); + +static PyObject * +cert_sha256_digest(PyObject *self, PyObject *args); + +static PyObject * +cert_sha512_digest(PyObject *self, PyObject *args); + +/* ==================================== */ + +static char * +key_type_str(KeyType key_type) +{ + switch(key_type) { + case nullKey: return "NULL"; + case rsaKey: return "RSA"; + case dsaKey: return "DSA"; + case fortezzaKey: return "Fortezza"; + case dhKey: return "Diffie Helman"; + case keaKey: return "Key Exchange Algorithm"; + case ecKey: return "Elliptic Curve"; + } + return "unknown"; +} + +PyDoc_STRVAR(generic_format_doc, +"format(level=0, indent=' ') -> string)\n\ +\n\ +:Parameters:\n\ + level : integer\n\ + Initial indentation level, all subsequent indents are relative\n\ + to this starting level.\n\ + indent : string\n\ + string replicated once for each indent level then prepended to output line\n\ +\n\ +This is equivalent to:\n\ +nss.indented_format(cert.signed_data.format_lines())\n\ +"); + +PyDoc_STRVAR(generic_format_lines_doc, +"format_lines(level=0) -> [(level, string),...]\n\ +\n\ +:Parameters:\n\ + level : integer\n\ + Initial indentation level, all subsequent indents are relative\n\ + to this starting level.\n\ +\n\ +Formats the object into a sequence of lines with indent level\n\ +information. The return value is a list where each list item is a 2\n\ +valued tuple pair. The first item in the pair is an integer\n\ +representing the indentation level for that line and the second item\n\ +in the pair is the string value for the line.\n\ +\n\ +The output of this function can be formatted into a single string\n\ +by calling nss.indented_format(). The reason this function returns\n\ +(level, string) pairs as opposed to an single indented string is to\n\ +support other text formatting systems with indentation controls.\n\ +"); + +static PyObject * +fmt_pair(int level, char *label, PyObject *obj) +{ + PyObject *pair = NULL; + PyObject *obj_str = NULL; + + if (PyString_Check(obj)) { + Py_INCREF(obj); + obj_str = obj; + } else { + if ((obj_str = PyObject_Str(obj)) == NULL) + return NULL; + } + + if (label) { + PyObject *labeled_str = NULL; + + if (obj_str) { + if ((labeled_str = PyString_FromFormat("%s: %s", label, PyString_AsString(obj_str))) == NULL) { + Py_DECREF(obj_str); + return NULL; + } + Py_DECREF(obj_str); + obj_str = labeled_str; + } else { + if ((obj_str = PyString_FromFormat("%s:", label)) == NULL) { + return NULL; + } + } + } + + if (!obj_str) { + if ((obj_str = PyString_FromString("None")) == NULL) { + return NULL; + } + } + + if ((pair = PyTuple_New(2)) == NULL) { + return NULL; + } + + PyTuple_SET_ITEM(pair, 0, PyInt_FromLong(level)); + PyTuple_SET_ITEM(pair, 1, obj_str); + + return pair; +} + +static PyObject * +fmt_label(int level, char *label) +{ + PyObject *pair = NULL; + PyObject *label_str = NULL; + + if ((label_str = PyString_FromFormat("%s:", label)) == NULL) { + return NULL; + } + + if ((pair = PyTuple_New(2)) == NULL) { + return NULL; + } + + PyTuple_SET_ITEM(pair, 0, PyInt_FromLong(level)); + PyTuple_SET_ITEM(pair, 1, label_str); + + return pair; +} + + +static PyObject * +format_from_lines(format_lines_func formatter, PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", "indent", NULL}; + int level = 0; + PyObject *py_indent = NULL; + PyObject *py_lines = NULL; + PyObject *py_formatted_result = NULL; + PyObject *tmp_args = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iS:format", kwlist, &level, &py_indent)) + return NULL; + + if (!py_indent) { + if ((py_indent = PyString_FromString(" ")) == NULL) + goto fail; + } else { + Py_INCREF(py_indent); + } + + if ((tmp_args = Py_BuildValue("(i)", level)) == NULL) + goto fail; + if ((py_lines = formatter(self, tmp_args, NULL)) == NULL) + goto fail; + + if ((tmp_args = Py_BuildValue("OO", py_lines, py_indent)) == NULL) + goto fail; + if ((py_formatted_result = nss_indented_format(NULL, tmp_args, NULL)) == NULL) + goto fail; + + Py_DECREF(tmp_args); + Py_DECREF(py_indent); + return py_formatted_result; + + fail: + Py_XDECREF(tmp_args); + Py_XDECREF(py_indent); + return NULL; +} + +static PyObject * +obj_to_hex(PyObject *obj, int octets_per_line, char *separator) +{ + unsigned char *data = NULL; + Py_ssize_t data_len; + + if (PyObject_AsReadBuffer(obj, (void *)&data, &data_len)) + return NULL; + + return raw_data_to_hex(data, data_len, octets_per_line, separator); + +} + +static PyObject * +raw_data_to_hex(unsigned char *data, int data_len, int octets_per_line, char *separator) +{ + int separator_len = 0; + char *separator_end = NULL; + char *src=NULL, *dst=NULL; + int line_size = 0; + unsigned char octet = 0; + int num_lines = 0; + PyObject *lines = NULL; + PyObject *line = NULL; + int line_number, i, j; + int num_octets = 0; + + + if (octets_per_line < 0) + octets_per_line = OCTETS_PER_LINE_DEFAULT; + + if (!separator) + separator = HEX_SEPARATOR_DEFAULT; + + separator_len = strlen(separator); + separator_end = separator + separator_len; + + if (octets_per_line <= 0) { + num_octets = data_len; + line_size = (num_octets * 2) + ((num_octets-1) * separator_len); + + if ((line = PyString_FromStringAndSize(NULL, line_size)) == NULL) { + return NULL; + } + dst = PyString_AS_STRING(line); + for (i = 0; i < data_len; i++) { + octet = data[i]; + *dst++ = hex_chars[(octet & 0xF0) >> 4]; + *dst++ = hex_chars[octet & 0xF]; + if (i < data_len-1) + for (src = separator; src < separator_end; *dst++ = *src++); + } + return line; + } else { + num_lines = (data_len + octets_per_line - 1) / octets_per_line; + + if ((lines = PyList_New(num_lines)) == NULL) { + return NULL; + } + + for (i = line_number = 0; i < data_len;) { + num_octets = data_len - i; + if (num_octets > octets_per_line) { + num_octets = octets_per_line; + line_size = num_octets*(2+separator_len); + } else { + line_size = (num_octets * 2) + ((num_octets-1) * separator_len); + } + if ((line = PyString_FromStringAndSize(NULL, line_size)) == NULL) { + Py_DECREF(lines); + return NULL; + } + dst = PyString_AS_STRING(line); + for (j = 0; j < num_octets && i < data_len; i++, j++) { + octet = data[i]; + *dst++ = hex_chars[(octet & 0xF0) >> 4]; + *dst++ = hex_chars[octet & 0xF]; + if (i < data_len-1) + for (src = separator; src < separator_end; *dst++ = *src++); + } + PyList_SetItem(lines, line_number++, line); + } + return lines; + } +} + +static PyObject * +cert_data_to_hex(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"data", "octets_per_line", "separator", NULL}; + PyObject *obj = NULL; + int octets_per_line = -1; + char *separator = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|is:cert_data_to_hex", kwlist, + &obj, &octets_per_line, &separator)) + return NULL; + + return obj_to_hex(obj, octets_per_line, separator); +} + +static SECStatus +sec_strip_tag_and_length(SECItem *item) +{ + unsigned int start; + + if (!item || !item->data || item->len < 2) { /* must be at least tag and length */ + return SECFailure; + } + start = ((item->data[1] & 0x80) ? (item->data[1] & 0x7f) + 2 : 2); + if (item->len < start) { + return SECFailure; + } + item->data += start; + item->len -= start; + return SECSuccess; +} + +static PyObject * +sec_context_specific_str(SECItem *item) +{ + PyObject *str = NULL; + PyObject *hex_str = NULL; + int type = item->data[0] & SEC_ASN1_TAGNUM_MASK; + int constructed = item->data[0] & SEC_ASN1_CONSTRUCTED; + SECItem tmp; + + if (constructed) { + str = PyString_FromFormat("[%d]", type); + } else { + tmp = *item; + if (sec_strip_tag_and_length(&tmp) == SECSuccess) { + if ((hex_str = raw_data_to_hex(tmp.data, tmp.len, 0, NULL))) { + str = PyString_FromFormat("[%d] %s", type, PyString_AsString(hex_str)); + Py_DECREF(hex_str); + } + } + if (!str) { + str = PyString_FromFormat("[%d]", type); + } + } + + return str; +} + +static PyObject * +sec_any_str(SECItem *item) +{ + if (item && item->len && item->data) { + switch (item->data[0] & SEC_ASN1_CLASS_MASK) { + case SEC_ASN1_CONTEXT_SPECIFIC: + return sec_context_specific_str(item); + break; + case SEC_ASN1_UNIVERSAL: + return sec_universal_item_str(item); + break; + default: + return raw_data_to_hex(item->data, item->len, 0, NULL); + } + } + return PyString_FromString("(null)"); +} + + +/* return a ASN1 SET or SEQUENCE as a list of strings */ +static PyObject * +sec_set_str_list(SECItem *item) +{ + int type = item->data[0] & SEC_ASN1_TAGNUM_MASK; + int constructed = item->data[0] & SEC_ASN1_CONSTRUCTED; + char *label = NULL; + SECItem stripped_item = *item; + PyObject *py_items = NULL; + PyObject *py_item = NULL; + + if (!constructed) { + return raw_data_to_hex(item->data, item->len, 0, NULL); + } + + if (sec_strip_tag_and_length(&stripped_item) != SECSuccess) + Py_RETURN_NONE; + + if ((py_items = PyList_New(0)) == NULL) + return NULL; + + if (type == SEC_ASN1_SET) + label = "Set "; + else if (type == SEC_ASN1_SEQUENCE) + label = "Sequence "; + else + label = ""; + + while (stripped_item.len >= 2) { + SECItem tmp_item = stripped_item; + + if (tmp_item.data[1] & 0x80) { + unsigned int i; + unsigned int len = tmp_item.data[1] & 0x7f; + if (len > sizeof tmp_item.len) + break; + tmp_item.len = 0; + for (i = 0; i < len; i++) { + tmp_item.len = (tmp_item.len << 8) | tmp_item.data[2+i]; + } + tmp_item.len += len + 2; + } else { + tmp_item.len = tmp_item.data[1] + 2; + } + if (tmp_item.len > stripped_item.len) { + tmp_item.len = stripped_item.len; + } + stripped_item.data += tmp_item.len; + stripped_item.len -= tmp_item.len; + + py_item = sec_any_str(&tmp_item); + PyList_Append(py_items, py_item); + } + + return py_items; +} + +static PyObject * +sec_boolean_str(SECItem *item) +{ + int val = 0; + + if (item->data && item->len) { + val = item->data[0]; + } + + if (val) + return PyString_FromString("True"); + else + return PyString_FromString("False"); +} + +static PyObject * +sec_encoded_boolean_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + + if (sec_strip_tag_and_length(&stripped_item) == SECSuccess) + str = sec_boolean_str(&stripped_item); + + return str; +} + +static PyObject * +sec_integer_str(SECItem *item) +{ + PyObject *str = NULL; + int ival; + + if (!item || !item->len || !item->data) { + str = PyString_FromFormat("(null)"); + } else if (item->len > 4) { + str = raw_data_to_hex(item->data, item->len, 0, NULL); + } else { + ival = DER_GetInteger(item); + str = PyString_FromFormat("%d (0x%x)", ival, ival); + } + return str; +} + +static PyObject * +sec_encoded_integer_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + + if (sec_strip_tag_and_length(&stripped_item) == SECSuccess) + str = sec_integer_str(&stripped_item); + + return str; +} + +static PyObject * +sec_string_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + + if (sec_strip_tag_and_length(&stripped_item) == SECSuccess) + str = PyString_FromStringAndSize((char *)item->data, item->len); + + return str; +} + +/* This function does NOT expect a DER type and length. */ +static PyObject * +sec_oid_str(SECItem *oid) +{ + SECOidData *oiddata; + char *oidString = NULL; + PyObject *py_oid_str = NULL; + + if ((oiddata = SECOID_FindOID(oid)) != NULL) { + return PyString_FromString(oiddata->desc); + } + if ((oidString = CERT_GetOidString(oid)) != NULL) { + py_oid_str = PyString_FromString(oidString); + PR_smprintf_free(oidString); + return py_oid_str; + } + Py_RETURN_NONE; +} + +static PyObject * +sec_encoded_oid_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + + if (sec_strip_tag_and_length(&stripped_item) == SECSuccess) + str = sec_oid_str(&stripped_item); + + return str; +} + +static PyObject * +sec_utc_time_str(SECItem *item) +{ + PRTime pr_time = 0; + PRExplodedTime exploded_time; + char time_str[100]; + + if ((DER_UTCTimeToTime(&pr_time, item) != SECSuccess)) + Py_RETURN_NONE; + PR_ExplodeTime(pr_time, PR_GMTParameters, &exploded_time); + PR_FormatTime(time_str, sizeof(time_str), time_format, &exploded_time); + + return PyString_FromString(time_str); +} + + +static PyObject * +sec_generalized_time_str(SECItem *item) +{ + PRTime pr_time = 0; + PRExplodedTime exploded_time; + char time_str[100]; + + if ((DER_GeneralizedTimeToTime(&pr_time, item) != SECSuccess)) + Py_RETURN_NONE; + PR_ExplodeTime(pr_time, PR_GMTParameters, &exploded_time); + PR_FormatTime(time_str, sizeof(time_str), time_format, &exploded_time); + + return PyString_FromString(time_str); +} + + +PRTime +sec_time_choice(SECItem *item) +{ + PRTime pr_time = 0; + + switch (item->type) { + case siUTCTime: + DER_UTCTimeToTime(&pr_time, item); + break; + case siGeneralizedTime: + DER_GeneralizedTimeToTime(&pr_time, item); + break; + default: + PyErr_SetString(PyExc_ValueError, "unknown sec ANS.1 time type"); + } + return pr_time; +} + +static PyObject * +sec_time_choice_str(SECItem *item) +{ + PRTime pr_time = 0; + PRExplodedTime exploded_time; + char time_str[100]; + + pr_time = sec_time_choice(item); + PR_ExplodeTime(pr_time, PR_GMTParameters, &exploded_time); + PR_FormatTime(time_str, sizeof(time_str), time_format, &exploded_time); + + return PyString_FromString(time_str); +} + +static PyObject * +sec_octet_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + + if (sec_strip_tag_and_length(&stripped_item) == SECSuccess) + str = raw_data_to_hex(item->data, item->len, 0, NULL); + + return str; +} + +static PyObject * +sec_bit_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + int unused_bits; + + if (sec_strip_tag_and_length(&stripped_item) != SECSuccess || stripped_item.len < 2) + Py_RETURN_NONE; + + unused_bits = *stripped_item.data++; + stripped_item.len--; + + str = raw_data_to_hex(stripped_item.data, stripped_item.len, 0, NULL); + + if (unused_bits) { + PyString_ConcatAndDel(&str, PyString_FromFormat("(%d least significant bits unused)", unused_bits)); + } + + return str; +} + +static PyObject * +sec_bmp_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp_item = {0, 0, 0}; + + if (sec_strip_tag_and_length(&stripped_item) != SECSuccess) + goto loser; + + if (stripped_item.len % 2) + goto loser; + + len = (int)(stripped_item.len / 2); + tmp_item.data = (unsigned char *)PORT_Alloc(len); + + if (!tmp_item.data) + goto loser; + + tmp_item.len = len; + + for (s = stripped_item.data, d = tmp_item.data ; len > 0; len--) { + PRUint32 tmp_char = (s[0] << 8) | s[1]; s += 2; + if (!isprint(tmp_char)) + goto loser; + *d++ = (unsigned char)tmp_char; + } + str = PyString_FromString((char *)tmp_item.data); + PORT_Free(tmp_item.data); + return str; + +loser: + str = raw_data_to_hex(stripped_item.data, stripped_item.len, 0, NULL); + if (tmp_item.data) + PORT_Free(tmp_item.data); + return str; +} + +static PyObject * +sec_universal_str(SECItem *item) +{ + PyObject *str = NULL; + SECItem stripped_item = *item; + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp_item = {0, 0, 0}; + + if (sec_strip_tag_and_length(&stripped_item) != SECSuccess) + goto loser; + + if (stripped_item.len % 4) + goto loser; + + len = (int)(stripped_item.len / 4); + tmp_item.data = (unsigned char *)PORT_Alloc(len); + + if (!tmp_item.data) + goto loser; + + tmp_item.len = len; + + for (s = stripped_item.data, d = tmp_item.data ; len > 0; len--) { + PRUint32 tmp_char = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; + if (!isprint(tmp_char)) + goto loser; + *d++ = (unsigned char)tmp_char; + } + str = PyString_FromString((char *)tmp_item.data); + PORT_Free(tmp_item.data); + return str; + +loser: + str = raw_data_to_hex(stripped_item.data, stripped_item.len, 0, NULL); + if (tmp_item.data) + PORT_Free(tmp_item.data); + return str; +} + +static PyObject * +sec_universal_item_str(SECItem *item) +{ + switch (item->data[0] & SEC_ASN1_TAGNUM_MASK) { + case SEC_ASN1_ENUMERATED: + case SEC_ASN1_INTEGER: + return sec_encoded_integer_str(item); + case SEC_ASN1_OBJECT_ID: + return sec_encoded_oid_str(item); + case SEC_ASN1_BOOLEAN: + return sec_encoded_boolean_str(item); + case SEC_ASN1_UTF8_STRING: + case SEC_ASN1_PRINTABLE_STRING: + case SEC_ASN1_VISIBLE_STRING: + case SEC_ASN1_IA5_STRING: + case SEC_ASN1_T61_STRING: + return sec_string_str(item); + case SEC_ASN1_GENERALIZED_TIME: + return sec_generalized_time_str(item); + case SEC_ASN1_UTC_TIME: + return sec_utc_time_str(item); + case SEC_ASN1_NULL: + return PyString_FromString("(null)"); + case SEC_ASN1_SET: + case SEC_ASN1_SEQUENCE: + return sec_set_str_list(item); + case SEC_ASN1_OCTET_STRING: + return sec_octet_str(item); + case SEC_ASN1_BIT_STRING: + sec_bit_str(item); + break; + case SEC_ASN1_BMP_STRING: + return sec_bmp_str(item); + case SEC_ASN1_UNIVERSAL_STRING: + return sec_universal_str(item); + default: + return raw_data_to_hex(item->data, item->len, 0, NULL); + } + Py_RETURN_NONE; +} + +static PyObject * +get_algorithm_id_str(SECAlgorithmID *a) +{ + PyObject *str = NULL; + + if ((str = sec_oid_str(&a->algorithm)) == NULL) + Py_RETURN_NONE; + + if ((a->parameters.len == 0) || + (a->parameters.len == 2 && memcmp(a->parameters.data, "\005\000", 2) == 0)) { + /* No arguments or NULL argument */ + } else { + /* Print args to algorithm */ + PyObject *hex_args = NULL; + + if ((hex_args = raw_data_to_hex(a->parameters.data, a->parameters.len, 0, NULL)) != NULL) { + PyString_ConcatAndDel(&str, hex_args); + } + } + return str; +} + + +static PyObject * +cert_trust_flags_str(unsigned int flags) +{ + PyObject *py_flags = NULL; + PyObject *py_flag = NULL; + + if ((py_flags = PyList_New(0)) == NULL) + return NULL; + + if (flags & CERTDB_VALID_PEER) { + if ((py_flag = PyString_FromString("Valid Peer")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_TRUSTED) { + if ((py_flag = PyString_FromString("Trusted")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_SEND_WARN) { + if ((py_flag = PyString_FromString("Warn When Sending")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_VALID_CA) { + if ((py_flag = PyString_FromString("Valid CA")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_TRUSTED_CA) { + if ((py_flag = PyString_FromString("Trusted CA")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_NS_TRUSTED_CA) { + if ((py_flag = PyString_FromString("Netscape Trusted CA")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_USER) { + if ((py_flag = PyString_FromString("User")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_TRUSTED_CLIENT_CA) { + if ((py_flag = PyString_FromString("Trusted Client CA")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + if (flags & CERTDB_GOVT_APPROVED_CA) { + if ((py_flag = PyString_FromString("Step-up")) == NULL) { + Py_DECREF(py_flags); + return NULL; + } + PyList_Append(py_flags, py_flag); + } + return py_flags; +} + +static PyObject * +data_to_buffer(unsigned char *data, Py_ssize_t len) +{ + PyObject *buf = NULL; + Py_ssize_t buf_len; + void* raw_buffer; + + if ((buf = PyBuffer_New(len)) == NULL) + return NULL; + + if (PyObject_AsWriteBuffer(buf, &raw_buffer, &buf_len) || buf_len < len) { + Py_DECREF(buf); + return NULL; + } + + memcpy(raw_buffer, data, len); + return buf; +} + +/* ========================================================================== */ +/* =============================== SecItem Class ============================ */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static +PyGetSetDef SecItem_getseters[] = { + {NULL} /* Sentinel */ +}; + +static PyMemberDef SecItem_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyMethodDef SecItem_methods[] = { + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +SecItem_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + SecItem *self; + + TraceObjNewEnter("SecItem_new", type); + + if ((self = (SecItem *)type->tp_alloc(type, 0)) == NULL) return NULL; + self->item.type = 0; + self->item.len = 0; + self->item.data = NULL; + self->kind = SECITEM_unknown; + + TraceObjNewLeave("SecItem_new", self); + return (PyObject *)self; +} + +static void +SecItem_dealloc(SecItem* self) +{ + TraceMethodEnter("SecItem_dealloc", self); + + if (self->item.data) { + PyMem_FREE(self->item.data); + } + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(SecItem_doc, +"DER encoded data. Used internally by NSS"); + +static int +SecItem_init(SecItem *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("SecItem_init", self); + + return 0; +} + +static PyObject * +SecItem_repr(SecItem *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyObject * +SecItem_str(SecItem *self) +{ + PyObject *return_value = NULL; + + switch(self->kind) { + case SECITEM_dist_name: + { + char *name; + + if ((name = CERT_DerNameToAscii(&self->item)) == NULL) { + return set_nspr_error(NULL); + } + return_value = PyString_FromString(name); + PORT_Free(name); + } + break; + case SECITEM_algorithm: + return sec_oid_str(&self->item); + default: + return_value = PyString_Encode((char *)self->item.data, self->item.len, "hex", NULL); + break; + } + return return_value; +} + +/* =========================== Buffer Protocol ========================== */ + +static Py_ssize_t +SecItem_buffer_getbuf(PyObject *obj, Py_ssize_t index, void **ptr) +{ + SecItem *self = (SecItem *) obj; + if (index != 0) { + PyErr_SetString(PyExc_SystemError, "Accessing non-existent segment"); + return -1; + } + *ptr = self->item.data; + return self->item.len; +} + +static Py_ssize_t +SecItem_buffer_getsegcount(PyObject *obj, Py_ssize_t *lenp) +{ + if (lenp) + *lenp = 1; + return 1; +} + +static PyBufferProcs SecItem_as_buffer = { + SecItem_buffer_getbuf, /* bf_getreadbuffer */ + SecItem_buffer_getbuf, /* bf_getwritebuffer */ + SecItem_buffer_getsegcount, /* bf_getsegcount */ + NULL, /* bf_getcharbuffer */ +}; + +static Py_ssize_t +SecItem_sq_length(PyObject *obj) +{ + SecItem *self = (SecItem *) obj; + return self->item.len; +} + +static PySequenceMethods SecItem_as_sequence = { + SecItem_sq_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyTypeObject SecItemType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.SecItem", /* tp_name */ + sizeof(SecItem), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SecItem_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)SecItem_repr, /* tp_repr */ + 0, /* tp_as_number */ + &SecItem_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)SecItem_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &SecItem_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + SecItem_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + SecItem_methods, /* tp_methods */ + SecItem_members, /* tp_members */ + SecItem_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)SecItem_init, /* tp_init */ + 0, /* tp_alloc */ + SecItem_new, /* tp_new */ +}; + +PyObject * +SecItem_new_from_sec_item(SECItem *item, SECItemKind kind) +{ + SecItem *self = NULL; + + TraceObjNewEnter("SecItem_new_from_sec_item", NULL); + + if ((self = (SecItem *) SecItemType.tp_new(&SecItemType, NULL, NULL)) == NULL) + return NULL; + + self->item.type = item->type; + self->item.len = item->len; + if ((self->item.data = PyMem_MALLOC(item->len)) == NULL) { + return PyErr_NoMemory(); + } + memmove(self->item.data, item->data, item->len); + + self->kind = kind; + + TraceObjNewLeave("SecItem_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* ======================== SignatureAlgorithm Class ======================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static +PyGetSetDef SignatureAlgorithm_getseters[] = { + {NULL} /* Sentinel */ +}; + +static PyMemberDef SignatureAlgorithm_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyMethodDef SignatureAlgorithm_methods[] = { + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +SignatureAlgorithm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + SignatureAlgorithm *self; + + TraceObjNewEnter("SignatureAlgorithm_new", type); + + if ((self = (SignatureAlgorithm *)type->tp_alloc(type, 0)) == NULL) return NULL; + + memset(&self->id, 0, sizeof(self->id)); + self->py_id = NULL; + self->py_parameters = NULL; + + TraceObjNewLeave("SignatureAlgorithm_new", self); + return (PyObject *)self; +} + +static void +SignatureAlgorithm_dealloc(SignatureAlgorithm* self) +{ + TraceMethodEnter("SignatureAlgorithm_dealloc", self); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(SignatureAlgorithm_doc, +"An object representing a signature algorithm"); + +static int +SignatureAlgorithm_init(SignatureAlgorithm *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("SignatureAlgorithm_init", self); + + return 0; +} + +static PyObject * +SignatureAlgorithm_repr(SignatureAlgorithm *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyObject * +SignatureAlgorithm_str(SignatureAlgorithm *self) +{ + return get_algorithm_id_str(&self->id); +} + +static PyTypeObject SignatureAlgorithmType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.SignatureAlgorithm", /* tp_name */ + sizeof(SignatureAlgorithm), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SignatureAlgorithm_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)SignatureAlgorithm_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)SignatureAlgorithm_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + SignatureAlgorithm_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + SignatureAlgorithm_methods, /* tp_methods */ + SignatureAlgorithm_members, /* tp_members */ + SignatureAlgorithm_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)SignatureAlgorithm_init, /* tp_init */ + 0, /* tp_alloc */ + SignatureAlgorithm_new, /* tp_new */ +}; + +PyObject * +SignatureAlgorithm_new_from_algorithm_id(SECAlgorithmID *id) +{ + SignatureAlgorithm *self = NULL; + + TraceObjNewEnter("SignatureAlgorithm_new_from_sec_item", NULL); + + if ((self = (SignatureAlgorithm *) SignatureAlgorithmType.tp_new(&SignatureAlgorithmType, NULL, NULL)) == NULL) + return NULL; + + self->id = *id; + if ((self->py_id = SecItem_new_from_sec_item(&id->algorithm, SECITEM_algorithm)) == NULL) + return NULL; + if ((self->py_parameters = SecItem_new_from_sec_item(&id->parameters, SECITEM_unknown)) == NULL) + return NULL; + + TraceObjNewLeave("SignatureAlgorithm_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* ============================ KEYPQGParams Class ========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +KEYPQGParams_get_prime(KEYPQGParams *self, void *closure) +{ + Py_INCREF(self->py_prime); + return self->py_prime; +} + +static PyObject * +KEYPQGParams_get_subprime(KEYPQGParams *self, void *closure) +{ + Py_INCREF(self->py_subprime); + return self->py_subprime; +} + +static PyObject * +KEYPQGParams_get_base(KEYPQGParams *self, void *closure) +{ + Py_INCREF(self->py_base); + return self->py_base; +} + +static +PyGetSetDef KEYPQGParams_getseters[] = { + {"prime", (getter)KEYPQGParams_get_prime, (setter)NULL, "key prime value, also known as p", NULL}, + {"subprime", (getter)KEYPQGParams_get_subprime, (setter)NULL, "key subprime value, also known as q", NULL}, + {"base", (getter)KEYPQGParams_get_base, (setter)NULL, "key base value, also known as g", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef KEYPQGParams_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyMethodDef KEYPQGParams_methods[] = { + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +KEYPQGParams_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + KEYPQGParams *self; + + TraceObjNewEnter("KEYPQGParams_new", type); + + if ((self = (KEYPQGParams *)type->tp_alloc(type, 0)) == NULL) return NULL; + + self->py_prime = NULL; + self->py_subprime = NULL; + self->py_base = NULL; + + TraceObjNewLeave("KEYPQGParams_new", self); + return (PyObject *)self; +} + +static void +KEYPQGParams_dealloc(KEYPQGParams* self) +{ + TraceMethodEnter("KEYPQGParams_dealloc", self); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(KEYPQGParams_doc, +"An object representing key parameters\n\ + - prime (also known as p)\n\ + - subprime (also known as q)\n\ + - base (also known as g)\n\ +"); + +static int +KEYPQGParams_init(KEYPQGParams *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("KEYPQGParams_init", self); + + return 0; +} + +static PyObject * +KEYPQGParams_repr(KEYPQGParams *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyObject * +KEYPQGParams_str(KEYPQGParams *self) +{ + PyObject *fmt = NULL; + PyObject *args = NULL; + PyObject *str = NULL; + + if ((fmt = PyString_FromString("prime(p)=%s subprime(q)=%s base(g)=%s")) == NULL) + return NULL; + if ((args = PyTuple_New(3)) == NULL) + return NULL; + + PyTuple_SET_ITEM(args, 0, PyObject_Str(self->py_prime)); + PyTuple_SET_ITEM(args, 1, PyObject_Str(self->py_subprime)); + PyTuple_SET_ITEM(args, 2, PyObject_Str(self->py_base)); + + str = PyString_Format(fmt, args); + + Py_DECREF(fmt); + Py_DECREF(args); + return str; +} + +static PyTypeObject KEYPQGParamsType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.KEYPQGParams", /* tp_name */ + sizeof(KEYPQGParams), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)KEYPQGParams_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)KEYPQGParams_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)KEYPQGParams_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + KEYPQGParams_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + KEYPQGParams_methods, /* tp_methods */ + KEYPQGParams_members, /* tp_members */ + KEYPQGParams_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)KEYPQGParams_init, /* tp_init */ + 0, /* tp_alloc */ + KEYPQGParams_new, /* tp_new */ +}; + +PyObject * +KEYPQGParams_new_from_SECKEYPQGParams(SECKEYPQGParams *params) +{ + KEYPQGParams *self = NULL; + + TraceObjNewEnter("KEYPQGParams_new_from_sec_item", NULL); + + if ((self = (KEYPQGParams *) KEYPQGParamsType.tp_new(&KEYPQGParamsType, NULL, NULL)) == NULL) + return NULL; + + if ((self->py_prime = SecItem_new_from_sec_item(¶ms->prime, SECITEM_unknown)) == NULL) + return NULL; + + if ((self->py_subprime = SecItem_new_from_sec_item(¶ms->subPrime, SECITEM_unknown)) == NULL) + return NULL; + + if ((self->py_base = SecItem_new_from_sec_item(¶ms->base, SECITEM_unknown)) == NULL) + return NULL; + + TraceObjNewLeave("KEYPQGParams_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* =========================== RSAPublicKey Class =========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +RSAPublicKey_get_modulus(RSAPublicKey *self, void *closure) +{ + Py_INCREF(self->py_modulus); + return self->py_modulus; +} + +static PyObject * +RSAPublicKey_get_exponent(RSAPublicKey *self, void *closure) +{ + Py_INCREF(self->py_exponent); + return self->py_exponent; +} + +static +PyGetSetDef RSAPublicKey_getseters[] = { + {"modulus", (getter)RSAPublicKey_get_modulus, (setter)NULL, "RSA modulus", NULL}, + {"exponent", (getter)RSAPublicKey_get_exponent, (setter)NULL, "RSA exponent", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef RSAPublicKey_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +RSAPublicKey_format_lines(RSAPublicKey *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + PyObject *obj_lines = NULL; + int i; + Py_ssize_t len; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) { + return NULL; + } + + FMT_LABEL_AND_APPEND(level, "Modulus", lines, fail); + + if ((obj = RSAPublicKey_get_modulus(self, NULL)) == NULL) + goto fail; + obj_lines = obj_to_hex(obj, -1, NULL); + Py_DECREF(obj); + + level += 1; + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + FMT_OBJ_AND_APPEND(level, NULL, obj, lines, fail); + } + + Py_DECREF(obj_lines); + return lines; + fail: + Py_XDECREF(obj); + Py_XDECREF(lines); + Py_XDECREF(obj_lines); + return NULL; +} + +static PyObject * +RSAPublicKey_format(RSAPublicKey *self, PyObject *args, PyObject *kwds) +{ + return format_from_lines((format_lines_func)RSAPublicKey_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +RSAPublicKey_str(RSAPublicKey *self) +{ + PyObject *py_formatted_result = NULL; + + py_formatted_result = RSAPublicKey_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + +static PyMethodDef RSAPublicKey_methods[] = { + {"format_lines", (PyCFunction)RSAPublicKey_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)RSAPublicKey_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +RSAPublicKey_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + RSAPublicKey *self; + + TraceObjNewEnter("RSAPublicKey_new", type); + + if ((self = (RSAPublicKey *)type->tp_alloc(type, 0)) == NULL) return NULL; + + self->py_modulus = NULL; + self->py_exponent = NULL; + + TraceObjNewLeave("RSAPublicKey_new", self); + return (PyObject *)self; +} + +static void +RSAPublicKey_dealloc(RSAPublicKey* self) +{ + TraceMethodEnter("RSAPublicKey_dealloc", self); + + Py_XDECREF(self->py_modulus); + Py_XDECREF(self->py_exponent); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(RSAPublicKey_doc, +"An object representing an RSA Public Key"); + +static int +RSAPublicKey_init(RSAPublicKey *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("RSAPublicKey_init", self); + + return 0; +} + +static PyObject * +RSAPublicKey_repr(RSAPublicKey *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyTypeObject RSAPublicKeyType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.RSAPublicKey", /* tp_name */ + sizeof(RSAPublicKey), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)RSAPublicKey_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)RSAPublicKey_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)RSAPublicKey_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + RSAPublicKey_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + RSAPublicKey_methods, /* tp_methods */ + RSAPublicKey_members, /* tp_members */ + RSAPublicKey_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)RSAPublicKey_init, /* tp_init */ + 0, /* tp_alloc */ + RSAPublicKey_new, /* tp_new */ +}; + +PyObject * +RSAPublicKey_new_from_SECKEYRSAPublicKey(SECKEYRSAPublicKey *rsa) +{ + RSAPublicKey *self = NULL; + + TraceObjNewEnter("RSAPublicKey_new_from_sec_item", NULL); + + if ((self = (RSAPublicKey *) RSAPublicKeyType.tp_new(&RSAPublicKeyType, NULL, NULL)) == NULL) + return NULL; + + if ((self->py_modulus = SecItem_new_from_sec_item(&rsa->modulus, SECITEM_unknown)) == NULL) + return NULL; + + if ((self->py_exponent = SecItem_new_from_sec_item(&rsa->publicExponent, SECITEM_unknown)) == NULL) + return NULL; + + TraceObjNewLeave("RSAPublicKey_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* =========================== DSAPublicKey Class =========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +DSAPublicKey_get_pqg_params(DSAPublicKey *self, void *closure) +{ + Py_INCREF(self->py_pqg_params); + return self->py_pqg_params; +} + +static PyObject * +DSAPublicKey_get_public_value(DSAPublicKey *self, void *closure) +{ + Py_INCREF(self->py_public_value); + return self->py_public_value; +} + +static +PyGetSetDef DSAPublicKey_getseters[] = { + {"pqg_params", (getter)DSAPublicKey_get_pqg_params, (setter)NULL, "DSA P,Q,G params as a KEYPQGParams object", NULL}, + {"public_value", (getter)DSAPublicKey_get_public_value, (setter)NULL, "DSA public_value", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef DSAPublicKey_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyMethodDef DSAPublicKey_methods[] = { + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +DSAPublicKey_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + DSAPublicKey *self; + + TraceObjNewEnter("DSAPublicKey_new", type); + + if ((self = (DSAPublicKey *)type->tp_alloc(type, 0)) == NULL) return NULL; + + self->py_pqg_params = NULL; + self->py_public_value = NULL; + + TraceObjNewLeave("DSAPublicKey_new", self); + return (PyObject *)self; +} + +static void +DSAPublicKey_dealloc(DSAPublicKey* self) +{ + TraceMethodEnter("DSAPublicKey_dealloc", self); + + Py_XDECREF(self->py_pqg_params); + Py_XDECREF(self->py_public_value); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(DSAPublicKey_doc, +"A object representing a DSA Public Key"); + +static int +DSAPublicKey_init(DSAPublicKey *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("DSAPublicKey_init", self); + + return 0; +} + +static PyObject * +DSAPublicKey_repr(DSAPublicKey *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyObject * +DSAPublicKey_str(DSAPublicKey *self) +{ + PyObject *fmt = NULL; + PyObject *args = NULL; + PyObject *str = NULL; + + if ((fmt = PyString_FromString("pqg_params=[%s] public_value=%s")) == NULL) + return NULL; + if ((args = PyTuple_New(2)) == NULL) + return NULL; + + PyTuple_SET_ITEM(args, 0, PyObject_Str(self->py_pqg_params)); + PyTuple_SET_ITEM(args, 1, PyObject_Str(self->py_public_value)); + + str = PyString_Format(fmt, args); + + Py_DECREF(fmt); + Py_DECREF(args); + return str; +} + +static PyTypeObject DSAPublicKeyType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.DSAPublicKey", /* tp_name */ + sizeof(DSAPublicKey), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)DSAPublicKey_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)DSAPublicKey_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)DSAPublicKey_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + DSAPublicKey_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + DSAPublicKey_methods, /* tp_methods */ + DSAPublicKey_members, /* tp_members */ + DSAPublicKey_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)DSAPublicKey_init, /* tp_init */ + 0, /* tp_alloc */ + DSAPublicKey_new, /* tp_new */ +}; + +PyObject * +DSAPublicKey_new_from_SECKEYDSAPublicKey(SECKEYDSAPublicKey *dsa) +{ + DSAPublicKey *self = NULL; + + TraceObjNewEnter("DSAPublicKey_new_from_sec_item", NULL); + + if ((self = (DSAPublicKey *) DSAPublicKeyType.tp_new(&DSAPublicKeyType, NULL, NULL)) == NULL) + return NULL; + + if ((self->py_pqg_params = KEYPQGParams_new_from_SECKEYPQGParams(&dsa->params)) == NULL) + return NULL; + + if ((self->py_public_value = SecItem_new_from_sec_item(&dsa->publicValue, SECITEM_unknown)) == NULL) + return NULL; + + TraceObjNewLeave("DSAPublicKey_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* ============================= SignedData Class =========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +SignedData_get_algorithm(SignedData *self, void *closure) +{ + Py_INCREF(self->py_algorithm); + return self->py_algorithm; +} + +static PyObject * +SignedData_get_signature(SignedData *self, void *closure) +{ + Py_INCREF(self->py_signature); + return self->py_signature; +} + +static +PyGetSetDef SignedData_getseters[] = { + {"algorithm", (getter)SignedData_get_algorithm, (setter)NULL, "signature algorithm as a SignatureAlgorithm object", NULL}, + {"signature", (getter)SignedData_get_signature, (setter)NULL, "signature as a SecItem object", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef SignedData_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +SignedData_format_lines(SignedData *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + PyObject *obj_lines = NULL; + int i; + Py_ssize_t len; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) { + return NULL; + } + + if ((obj = SignedData_get_algorithm(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level, "Signature Algorithm", obj, lines, fail); + Py_DECREF(obj); + + FMT_LABEL_AND_APPEND(level, "Signature Data", lines, fail); + + if ((obj = SignedData_get_signature(self, NULL)) == NULL) + goto fail; + obj_lines = obj_to_hex(obj, -1, NULL); + Py_DECREF(obj); + + level += 1; + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + FMT_OBJ_AND_APPEND(level, NULL, obj, lines, fail); + } + + Py_DECREF(obj_lines); + return lines; + fail: + Py_XDECREF(obj); + Py_XDECREF(lines); + Py_XDECREF(obj_lines); + return NULL; +} + +static PyObject * +SignedData_format(SignedData *self, PyObject *args, PyObject *kwds) +{ + return format_from_lines((format_lines_func)SignedData_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +SignedData_str(SignedData *self) +{ + PyObject *py_formatted_result = NULL; + + py_formatted_result = SignedData_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + +static PyMethodDef SignedData_methods[] = { + {"format_lines", (PyCFunction)SignedData_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)SignedData_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +SignedData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + SignedData *self; + + TraceObjNewEnter("SignedData_new", type); + + if ((self = (SignedData *)type->tp_alloc(type, 0)) == NULL) return NULL; + + self->py_data = NULL; + self->py_algorithm = NULL; + self->py_signature = NULL; + + if ((self->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE)) == NULL ) { + return PyErr_NoMemory(); + } + + memset(&self->signed_data, 0, sizeof(self->signed_data)); + + TraceObjNewLeave("SignedData_new", self); + return (PyObject *)self; +} + +static void +SignedData_dealloc(SignedData* self) +{ + TraceMethodEnter("SignedData_dealloc", self); + + Py_XDECREF(self->py_data); + Py_XDECREF(self->py_algorithm); + Py_XDECREF(self->py_signature); + + PORT_FreeArena(self->arena, PR_FALSE); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(SignedData_doc, +"A object representing a signature"); + +static int +SignedData_init(SignedData *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("SignedData_init", self); + + return 0; +} + +static PyObject * +SignedData_repr(SignedData *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyTypeObject SignedDataType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.SignedData", /* tp_name */ + sizeof(SignedData), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SignedData_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)SignedData_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)SignedData_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + SignedData_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + SignedData_methods, /* tp_methods */ + SignedData_members, /* tp_members */ + SignedData_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)SignedData_init, /* tp_init */ + 0, /* tp_alloc */ + SignedData_new, /* tp_new */ +}; + +PyObject * +SignedData_new_from_sec_item(SECItem *item) +{ + SignedData *self = NULL; + + TraceObjNewEnter("SignedData_new_from_sec_item", NULL); + + if ((self = (SignedData *) SignedDataType.tp_new(&SignedDataType, NULL, NULL)) == NULL) + return NULL; + + if (SEC_ASN1DecodeItem(self->arena, &self->signed_data, + SEC_ASN1_GET(CERT_SignedDataTemplate), item) != SECSuccess) { + return NULL; + } + + if ((self->py_data = SecItem_new_from_sec_item(&self->signed_data.data, SECITEM_unknown)) == NULL) + return NULL; + + if ((self->py_algorithm = SignatureAlgorithm_new_from_algorithm_id(&self->signed_data.signatureAlgorithm)) == NULL) + return NULL; + + DER_ConvertBitString(&self->signed_data.signature); + if ((self->py_signature = SecItem_new_from_sec_item(&self->signed_data.signature, SECITEM_signature)) == NULL) + return NULL; + + TraceObjNewLeave("SignedData_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* ============================= PublicKey Class ============================ */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +PublicKey_get_key_type(PublicKey *self, void *closure) +{ + return PyInt_FromLong(self->pk->keyType); +} + +static PyObject * +PublicKey_get_key_type_str(PublicKey *self, void *closure) +{ + return PyString_FromString(key_type_str(self->pk->keyType)); +} + +static PyObject * +PublicKey_get_rsa(PublicKey *self, void *closure) +{ + if (self->pk->keyType == rsaKey) { + Py_INCREF(self->py_rsa_key); + return self->py_rsa_key; + } else { + PyErr_Format(PyExc_AttributeError, "when '%.50s' object has key_type=%s there is no attribute 'rsa'", + self->ob_type->tp_name, key_type_str(self->pk->keyType)); + return NULL; + } +} + +static PyObject * +PublicKey_get_dsa(PublicKey *self, void *closure) +{ + if (self->pk->keyType == dsaKey) { + Py_INCREF(self->py_dsa_key); + return self->py_dsa_key; + } else { + PyErr_Format(PyExc_AttributeError, "when '%.50s' object has key_type=%s there is no attribute 'dsa'", + self->ob_type->tp_name, key_type_str(self->pk->keyType)); + return NULL; + } +} + +static +PyGetSetDef PublicKey_getseters[] = { + {"key_type", (getter)PublicKey_get_key_type, (setter)NULL, "key type (e.g. rsaKey, dsaKey, etc.) as an int", NULL}, + {"key_type_str", (getter)PublicKey_get_key_type_str, (setter)NULL, "key type as a string", NULL}, + {"rsa", (getter)PublicKey_get_rsa, (setter)NULL, "RSA key as a RSAPublicKey object", NULL}, + {"dsa", (getter)PublicKey_get_dsa, (setter)NULL, "RSA key as a RSAPublicKey object", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef PublicKey_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +PublicKey_format_lines(PublicKey *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + PyObject *obj_lines = NULL; + int i; + Py_ssize_t len; + PyObject *tmp_args = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) + goto fail; + + if ((tmp_args = Py_BuildValue("(i)", level)) == NULL) + goto fail; + + switch(self->pk->keyType) { /* FIXME: handle the other cases */ + case rsaKey: + FMT_LABEL_AND_APPEND(level, "RSA Public Key", lines, fail); + if ((obj_lines = RSAPublicKey_format_lines((RSAPublicKey *)self->py_rsa_key, tmp_args, NULL)) == NULL) + goto fail; + break; + case dsaKey: + break; + case fortezzaKey: + case dhKey: + case keaKey: + case ecKey: + case nullKey: + break; + } + Py_DECREF(tmp_args); + + if (obj_lines) { + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + PyList_Append(lines, obj); + } + + Py_DECREF(obj_lines); + } + return lines; + fail: + Py_XDECREF(obj); + Py_XDECREF(lines); + Py_XDECREF(obj_lines); + Py_XDECREF(tmp_args); + return NULL; +} + +static PyObject * +PublicKey_format(PublicKey *self, PyObject *args, PyObject *kwds) +{ + return format_from_lines((format_lines_func)PublicKey_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +PublicKey_str(PublicKey *self) +{ + PyObject *py_formatted_result = NULL; + + py_formatted_result = PublicKey_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + +static PyMethodDef PublicKey_methods[] = { + {"format_lines", (PyCFunction)PublicKey_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)PublicKey_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +PublicKey_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PublicKey *self; + + TraceObjNewEnter("PublicKey_new", type); + + if ((self = (PublicKey *)type->tp_alloc(type, 0)) == NULL) return NULL; + + self->py_pk11slot = NULL; + self->py_rsa_key = NULL; + self->py_dsa_key = NULL; + + memset(&self->pk, 0, sizeof(self->pk)); + + TraceObjNewLeave("PublicKey_new", self); + return (PyObject *)self; +} + +static void +PublicKey_dealloc(PublicKey* self) +{ + TraceMethodEnter("PublicKey_dealloc", self); + + Py_XDECREF(self->py_pk11slot); + Py_XDECREF(self->py_rsa_key); + Py_XDECREF(self->py_dsa_key); + + SECKEY_DestroyPublicKey(self->pk); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(PublicKey_doc, +"An object representing a Public Key"); + +static int +PublicKey_init(PublicKey *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("PublicKey_init", self); + + return 0; +} + +static PyObject * +PublicKey_repr(PublicKey *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyTypeObject PublicKeyType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.PublicKey", /* tp_name */ + sizeof(PublicKey), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PublicKey_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)PublicKey_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)PublicKey_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + PublicKey_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PublicKey_methods, /* tp_methods */ + PublicKey_members, /* tp_members */ + PublicKey_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PublicKey_init, /* tp_init */ + 0, /* tp_alloc */ + PublicKey_new, /* tp_new */ +}; + +PyObject * +PublicKey_new_from_SECKEYPublicKey(SECKEYPublicKey *pk) +{ + PublicKey *self = NULL; + + TraceObjNewEnter("PublicKey_new_from_sec_item", NULL); + + if ((self = (PublicKey *) PublicKeyType.tp_new(&PublicKeyType, NULL, NULL)) == NULL) + return NULL; + + + self->pk = pk; + + if (self->pk->pkcs11Slot) { + if ((self->py_pk11slot = PK11Slot_new_from_slotinfo(self->pk->pkcs11Slot)) == NULL) + return NULL; + } else { + Py_INCREF(Py_None); + self->py_pk11slot = Py_None; + + } + + switch(pk->keyType) { /* FIXME: handle the other cases */ + case rsaKey: + self->py_rsa_key = RSAPublicKey_new_from_SECKEYRSAPublicKey(&pk->u.rsa); + break; + case dsaKey: + self->py_dsa_key = DSAPublicKey_new_from_SECKEYDSAPublicKey(&pk->u.dsa); + break; + case fortezzaKey: + case dhKey: + case keaKey: + case ecKey: + case nullKey: + break; + } + + TraceObjNewLeave("PublicKey_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* ======================= SubjectPublicKeyInfo Class ======================= */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +SubjectPublicKeyInfo_get_algorithm(SubjectPublicKeyInfo *self, void *closure) +{ + Py_INCREF(self->py_algorithm); + return self->py_algorithm; +} + +static PyObject * +SubjectPublicKeyInfo_get_public_key(SubjectPublicKeyInfo *self, void *closure) +{ + Py_INCREF(self->py_public_key); + return self->py_public_key; +} + +static +PyGetSetDef SubjectPublicKeyInfo_getseters[] = { + {"algorithm", (getter)SubjectPublicKeyInfo_get_algorithm, (setter)NULL, "algorithm", NULL}, + {"public_key", (getter)SubjectPublicKeyInfo_get_public_key, (setter)NULL, "PublicKey object", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef SubjectPublicKeyInfo_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +SubjectPublicKeyInfo_format_lines(SubjectPublicKeyInfo *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + PyObject *obj_lines = NULL; + int i; + Py_ssize_t len; + PublicKey *py_public_key = NULL; + PyObject *tmp_args = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) { + return NULL; + } + + if ((obj = SubjectPublicKeyInfo_get_algorithm(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level, "Public Key Algorithm", obj, lines, fail); + + if ((py_public_key = (PublicKey *)SubjectPublicKeyInfo_get_public_key(self, NULL)) == NULL) + goto fail; + + if ((tmp_args = Py_BuildValue("(i)", level+1)) == NULL) + goto fail; + if ((obj_lines = PublicKey_format_lines((PublicKey *)py_public_key, tmp_args, NULL)) == NULL) + goto fail; + Py_DECREF(tmp_args); + + if (obj_lines) { + level += 1; + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + PyList_Append(lines, obj); + } + + Py_DECREF(obj_lines); + } + return lines; + fail: + Py_XDECREF(tmp_args); + Py_XDECREF(lines); + Py_XDECREF(obj_lines); + return NULL; +} + +static PyObject * +SubjectPublicKeyInfo_format(SubjectPublicKeyInfo *self, PyObject *args, PyObject *kwds) +{ + return format_from_lines((format_lines_func)SubjectPublicKeyInfo_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +SubjectPublicKeyInfo_str(SubjectPublicKeyInfo *self) +{ + PyObject *py_formatted_result = NULL; + + py_formatted_result = SubjectPublicKeyInfo_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + +static PyMethodDef SubjectPublicKeyInfo_methods[] = { + {"format_lines", (PyCFunction)SubjectPublicKeyInfo_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)SubjectPublicKeyInfo_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +SubjectPublicKeyInfo_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + SubjectPublicKeyInfo *self; + + TraceObjNewEnter("SubjectPublicKeyInfo_new", type); + + if ((self = (SubjectPublicKeyInfo *)type->tp_alloc(type, 0)) == NULL) return NULL; + + self->py_algorithm = NULL; + self->py_public_key = NULL; + + TraceObjNewLeave("SubjectPublicKeyInfo_new", self); + return (PyObject *)self; +} + +static void +SubjectPublicKeyInfo_dealloc(SubjectPublicKeyInfo* self) +{ + TraceMethodEnter("SubjectPublicKeyInfo_dealloc", self); + + Py_XDECREF(self->py_algorithm); + Py_XDECREF(self->py_public_key); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(SubjectPublicKeyInfo_doc, +"An object representing a Subject Public Key"); + +static int +SubjectPublicKeyInfo_init(SubjectPublicKeyInfo *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("SubjectPublicKeyInfo_init", self); + + return 0; +} + +static PyObject * +SubjectPublicKeyInfo_repr(SubjectPublicKeyInfo *self) +{ + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyTypeObject SubjectPublicKeyInfoType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.SubjectPublicKeyInfo", /* tp_name */ + sizeof(SubjectPublicKeyInfo), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SubjectPublicKeyInfo_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)SubjectPublicKeyInfo_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)SubjectPublicKeyInfo_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + SubjectPublicKeyInfo_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + SubjectPublicKeyInfo_methods, /* tp_methods */ + SubjectPublicKeyInfo_members, /* tp_members */ + SubjectPublicKeyInfo_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)SubjectPublicKeyInfo_init, /* tp_init */ + 0, /* tp_alloc */ + SubjectPublicKeyInfo_new, /* tp_new */ +}; + +PyObject * +SubjectPublicKeyInfo_new_from_CERTSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki) +{ + SubjectPublicKeyInfo *self = NULL; + SECKEYPublicKey *pk = NULL; + + TraceObjNewEnter("SubjectPublicKeyInfo_new_from_sec_item", NULL); + + if ((self = (SubjectPublicKeyInfo *) SubjectPublicKeyInfoType.tp_new(&SubjectPublicKeyInfoType, NULL, NULL)) == NULL) + return NULL; + + if ((self->py_algorithm = SignatureAlgorithm_new_from_algorithm_id(&spki->algorithm)) == NULL) + return NULL; + + if ((pk = SECKEY_ExtractPublicKey(spki)) == NULL) { + Py_DECREF(self->py_algorithm); + return set_nspr_error(NULL); + } + + if ((self->py_public_key = PublicKey_new_from_SECKEYPublicKey(pk)) == NULL) { + Py_DECREF(self->py_algorithm); + return NULL; + } + + TraceObjNewLeave("SubjectPublicKeyInfo_new_from_sec_item", self); + return (PyObject *) self; +} + +/* ============================== Utilities ============================= */ + +CERTDistNames * +cert_distnames_as_CERTDistNames(PyObject *py_distnames) +{ + PRArenaPool *arena = NULL; + CERTDistNames *names = NULL; + int i; + SecItem *py_sec_item; + + if (!PySequence_Check(py_distnames)) { + PyErr_SetString(PyExc_TypeError, "cert distnames must be a sequence"); + return NULL; + } + + /* allocate an arena to use */ + if ((arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE)) == NULL ) { + PyErr_NoMemory(); + return NULL; + } + + /* allocate the header structure */ + if ((names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames))) == NULL) { + PORT_FreeArena(arena, PR_FALSE); + PyErr_NoMemory(); + return NULL; + } + + /* initialize the header struct */ + names->arena = arena; + names->head = NULL; + names->nnames = PySequence_Size(py_distnames); + names->names = NULL; + + /* construct the array from the list */ + if (names->nnames) { + names->names = (SECItem *)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem)); + + if (names->names == NULL) { + PORT_FreeArena(arena, PR_FALSE); + PyErr_NoMemory(); + return NULL; + } + + for (i = 0; i < names->nnames; i++) { + py_sec_item = (SecItem *)PySequence_GetItem(py_distnames, i); + if ((!PySecItem_Check(py_sec_item)) || (py_sec_item->kind != SECITEM_dist_name)) { + PyErr_Format(PyExc_TypeError, "item must be a %s containing a DistName", SecItemType.tp_name); + PORT_FreeArena(arena, PR_FALSE); + return NULL; + } + names->names[i] = py_sec_item->item; + } + } + return names; +} + +/* ========================================================================== */ +/* =============================== CertDB Class ============================= */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static +PyGetSetDef CertDB_getseters[] = { + {NULL} /* Sentinel */ +}; + +static PyMemberDef CertDB_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyMethodDef CertDB_methods[] = { + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +CertDB_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CertDB *self; + + TraceObjNewEnter("CertDB_new", type); + + if ((self = (CertDB *)type->tp_alloc(type, 0)) == NULL) return NULL; + self->handle = NULL; + + TraceObjNewLeave("CertDB_new", self); + return (PyObject *)self; +} + +static void +CertDB_dealloc(CertDB* self) +{ + TraceMethodEnter("CertDB_dealloc", self); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(CertDB_doc, +"An object representing a Certificate Database"); + +static int +CertDB_init(CertDB *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("CertDB_init", self); + return 0; +} + +static PyTypeObject CertDBType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.CertDB", /* tp_name */ + sizeof(CertDB), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)CertDB_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + CertDB_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CertDB_methods, /* tp_methods */ + CertDB_members, /* tp_members */ + CertDB_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)CertDB_init, /* tp_init */ + 0, /* tp_alloc */ + CertDB_new, /* tp_new */ +}; + +PyObject * +CertDB_new_from_handle(CERTCertDBHandle *cert_handle) +{ + CertDB *self = NULL; + + TraceObjNewEnter("CertDB_new_from_handle", NULL); + if ((self = (CertDB *) CertDBType.tp_new(&CertDBType, NULL, NULL)) == NULL) + return NULL; + + self->handle = cert_handle; + + TraceObjNewLeave("CertDB_new_from_handle", self); + return (PyObject *) self; +} + +PyObject * +cert_distnames_new_from_CERTDistNames(CERTDistNames *names) +{ + PyObject *py_distnames = NULL; + PyObject *py_sec_item = NULL; + int i, len; + + len = names->nnames; + if ((py_distnames = PyTuple_New(len)) == NULL) + return NULL; + + for (i = 0; i< names->nnames; i++) { + if ((py_sec_item = SecItem_new_from_sec_item(&names->names[i], SECITEM_dist_name)) == NULL) { + return NULL; + } + PyTuple_SetItem(py_distnames, i, py_sec_item); + } + + return py_distnames; +} + +/* ========================================================================== */ +/* ============================ Certificate Class =========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +Certificate_get_valid_not_before(Certificate *self, void *closure) +{ + PRTime pr_time = 0; + double d_time; + + pr_time = sec_time_choice(&self->cert->validity.notBefore); + LL_L2D(d_time, pr_time); + + return PyFloat_FromDouble(d_time); +} + +static PyObject * +Certificate_get_valid_not_before_str(Certificate *self, void *closure) +{ + return sec_time_choice_str(&self->cert->validity.notBefore); +} + +static PyObject * +Certificate_get_valid_not_after(Certificate *self, void *closure) +{ + PRTime pr_time = 0; + double d_time; + + pr_time = sec_time_choice(&self->cert->validity.notAfter); + LL_L2D(d_time, pr_time); + + return PyFloat_FromDouble(d_time); +} + +static PyObject * +Certificate_get_valid_not_after_str(Certificate *self, void *closure) +{ + return sec_time_choice_str(&self->cert->validity.notAfter); +} + +static PyObject * +Certificate_get_subject(Certificate *self, void *closure) +{ + char *subject; + PyObject *py_subject = NULL; + + subject = CERT_NameToAscii(&self->cert->subject); + py_subject = PyString_FromString(subject); + PORT_Free(subject); + + return py_subject; +} + +static PyObject * +Certificate_get_subject_common_name(Certificate *self, void *closure) +{ + char *cn; + PyObject *py_cn = NULL; + + cn = CERT_GetCommonName(&self->cert->subject); + if (cn == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + py_cn = PyString_FromString(cn); + PORT_Free(cn); + + return py_cn; +} + +static PyObject * +Certificate_get_issuer(Certificate *self, void *closure) +{ + char *issuer; + PyObject *py_issuer = NULL; + + issuer = CERT_NameToAscii(&self->cert->issuer); + py_issuer = PyString_FromString(issuer); + PORT_Free(issuer); + + return py_issuer; +} + +static PyObject * +Certificate_get_version(Certificate *self, void *closure) +{ + int version = 0; + + if (self->cert->version.len) { + version = DER_GetInteger(&self->cert->version); + } + + return PyInt_FromLong(version); +} + +static PyObject * +Certificate_get_serial_number(Certificate *self, void *closure) +{ + int serial_number = 0; + + if (self->cert->serialNumber.len) { + serial_number = DER_GetInteger(&self->cert->serialNumber); + } + + return PyInt_FromLong(serial_number); +} + +// FIXME: should this come from SignedData? +static PyObject * +Certificate_get_signature_algorithm(Certificate *self, void *closure) +{ + return SignatureAlgorithm_new_from_algorithm_id(&self->cert->signature); +} + +static PyObject * +Certificate_get_signed_data(Certificate *self, void *closure) +{ + PyObject *py_signed_data = NULL; + + return py_signed_data = SignedData_new_from_sec_item(&self->cert->derCert); +} + +static PyObject * +Certificate_get_der_data(Certificate *self, void *closure) +{ + PyObject *sig_buf = NULL; + SECItem der; + + der = self->cert->derCert; + sig_buf = data_to_buffer(der.data, der.len); + + return sig_buf; +} + +static PyObject * +Certificate_get_ssl_trust_str(Certificate *self, void *closure) +{ + if (self->cert->trust) + return cert_trust_flags_str(self->cert->trust->sslFlags); + else + Py_RETURN_NONE; +} + +static PyObject * +Certificate_get_email_trust_str(Certificate *self, void *closure) +{ + if (self->cert->trust) + return cert_trust_flags_str(self->cert->trust->emailFlags); + else + Py_RETURN_NONE; +} + +static PyObject * +Certificate_get_signing_trust_str(Certificate *self, void *closure) +{ + if (self->cert->trust) + return cert_trust_flags_str(self->cert->trust->objectSigningFlags); + else + Py_RETURN_NONE; +} + +static PyObject * +Certificate_get_subject_public_key_info(Certificate *self, void *closure) +{ + Py_INCREF(self->py_subject_public_key_info); + return self->py_subject_public_key_info; +} + +static +PyGetSetDef Certificate_getseters[] = { + {"valid_not_before", (getter)Certificate_get_valid_not_before, NULL, + "certificate not valid before this time (floating point value expressed as microseconds since the epoch, midnight January 1st 1970 UTC)", NULL}, + + {"valid_not_before_str", (getter)Certificate_get_valid_not_before_str, NULL, + "certificate not valid before this time (string value expressed, UTC)", NULL}, + + {"valid_not_after", (getter)Certificate_get_valid_not_after, NULL, + "certificate not valid after this time (floating point value expressed as microseconds since the epoch, midnight January 1st 1970, UTC)", NULL}, + + {"valid_not_after_str", (getter)Certificate_get_valid_not_after_str, NULL, + "certificate not valid after this time (string value expressed, UTC)", NULL}, + + {"subject", (getter)Certificate_get_subject, NULL, + "certificate subject", NULL}, + + {"subject_common_name", (getter)Certificate_get_subject_common_name, NULL, + "certificate subject", NULL}, + + {"issuer", (getter)Certificate_get_issuer, NULL, + "certificate issuer", NULL}, + + {"version", (getter)Certificate_get_version, NULL, + "certificate version", NULL}, + + {"serial_number", (getter)Certificate_get_serial_number, NULL, + "certificate serial number", NULL}, + + {"signature_algorithm", (getter)Certificate_get_signature_algorithm, NULL, + "certificate signature algorithm", NULL}, + + {"signed_data", (getter)Certificate_get_signed_data, NULL, + "certificate signature as SignedData object", NULL}, + + {"der_data", (getter)Certificate_get_der_data, NULL, + "raw certificate DER data as data buffer", NULL}, + + {"ssl_trust_str", (getter)Certificate_get_ssl_trust_str, NULL, + "certificate SSL trust flags as array of strings, or None if trust is not defined", NULL}, + + {"email_trust_str", (getter)Certificate_get_email_trust_str, NULL, + "certificate email trust flags as array of strings, or None if trust is not defined", NULL}, + + {"signing_trust_str", (getter)Certificate_get_signing_trust_str, NULL, + "certificate object signing trust flags as array of strings, or None if trust is not defined", NULL}, + + {"subject_public_key_info", (getter)Certificate_get_subject_public_key_info, NULL, "certificate public info as SubjectPublicKeyInfo object", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef Certificate_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +PyDoc_STRVAR(Certificate_find_kea_type_doc, +"find_kea_type() -> kea_type\n\ +Returns key exchange type of the keys in an SSL server certificate.\n\ +\n\ +May be one of the following:\n\ + - ssl_kea_null\n\ + - ssl_kea_rsa\n\ + - ssl_kea_dh\n\ + - ssl_kea_fortezza (deprecated)\n\ + - ssl_kea_ecdh\n\ +" +); +static PyObject * +Certificate_find_kea_type(Certificate *self, PyObject *args) +{ + return PyInt_FromLong(NSS_FindCertKEAType(self->cert)); +} + + +PyDoc_STRVAR(Certificate_verify_hostname_doc, +"verify_hostname(hostname) -> bool\n\ +\n\ +A restricted regular expression syntax is used to test if the common\n\ +name specified in the subject DN of the certificate is a match,\n\ +returning True if so, False otherwise.\n\ +\n\ +The regular expression systax is:\n\ + \\*\n\ + matches anything\n\ + \\?\n\ + matches one character\n\ + \\\\ (backslash)\n\ + escapes a special character\n\ + \\$\n\ + matches the end of the string\n\ + [abc]\n\ + matches one occurrence of a, b, or c. The only character\n\ + that needs to be escaped in this is ], all others are not special.\n\ + [a-z]\n\ + matches any character between a and z\n\ + [^az]\n\ + matches any character except a or z\n\ + \\~\n\ + followed by another shell expression removes any pattern matching\n\ + the shell expression from the match list\n\ + (foo|bar)\n\ + matches either the substring foo or the substring bar.\n\ + These can be shell expressions as well.\n\ +"); + +static PyObject * +Certificate_verify_hostname(Certificate *self, PyObject *args) +{ + char *hostname; + SECStatus sec_status; + + TraceMethodEnter("verify_hostname", self); + + if (!PyArg_ParseTuple(args, "s:verify_hostname", &hostname)) + return NULL; + + sec_status = CERT_VerifyCertName(self->cert, hostname); + + if (sec_status == SECSuccess) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE;; +} + +PyDoc_STRVAR(Certificate_has_signer_in_ca_names_doc, +"has_signer_in_ca_names(ca_names) -> bool\n\ +\n\ +:Parameters:\n\ + ca_names : (SecItem, ...)\n\ + Sequence of CA distinguished names. Each item in the sequence must\n\ + be a SecItem object containing a distinguished name.\n\ +\n\ +Returns True if any of the signers in the certificate chain for a\n\ +specified certificate are in the list of CA names, False\n\ +otherwise.\n\ +"); + +static PyObject * +Certificate_has_signer_in_ca_names(Certificate *self, PyObject *args) +{ + PyObject *py_ca_names = NULL; + CERTDistNames *ca_names = NULL; + SECStatus sec_status; + + TraceMethodEnter("has_signer_in_ca_names", self); + + if (!PyArg_ParseTuple(args, "s:has_signer_in_ca_names", py_ca_names)) + return NULL; + + if ((ca_names = cert_distnames_as_CERTDistNames(py_ca_names)) == NULL) { + } + + sec_status = NSS_CmpCertChainWCANames(self->cert, ca_names); + CERT_FreeDistNames(ca_names); + + if (sec_status == SECSuccess) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE;; +} + +PyDoc_STRVAR(Certificate_check_valid_times_doc, +"check_valid_times(time=now, allow_override=False) --> validity\n\ +\n\ +:Parameters:\n\ + time : number\n\ + an optional point in time as number of microseconds\n\ + since the NSPR epoch, midnight (00:00:00) 1 January\n\ + 1970 UTC, either as an integer or a float. If time \n\ + is not specified the current time is used.\n\ + allow_override : bool\n\ + If True then check to see if the invalidity has\n\ + been overridden by the user, defaults to False.\n\ +\n\ +Checks whether a specified time is within a certificate's validity\n\ +period.\n\ +\n\ +Returns one of:\n\ +\n\ +- secCertTimeValid\n\ +- secCertTimeExpired\n\ +- secCertTimeNotValidYet\n\ +"); + +static PyObject * +Certificate_check_valid_times(Certificate *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"time", NULL}; + PyObject *py_time = NULL; + int allow_override = 0; + PRTime time; + SECCertTimeValidity validity; + + TraceMethodEnter("check_valid_times", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:check_valid_times", kwlist, &py_time, &allow_override)) + return NULL; + + if (py_time) { + if (PyFloat_Check(py_time)) { + LL_D2L(time, PyFloat_AsDouble(py_time)); + } else if (PyInt_Check(py_time)) { + LL_I2L(time, PyInt_AsLong(py_time)); /* FIXME: should be PyLong_AsLongLong? */ + } else { + PyErr_SetString(PyExc_TypeError, "check_valid_times: time must be a float or an integer"); + return NULL; + } + } else { + time = PR_Now(); + } + + validity = CERT_CheckCertValidTimes(self->cert, time, allow_override); + + return PyInt_FromLong(validity); +} + +#if 0 +extern SECStatus +CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, + PRBool checkSig, SECCertificateUsage requiredUsages, + int64 t, void *wincx, CERTVerifyLog *log, + SECCertificateUsage* returnedUsages); + +/* same as above, but uses current time */ +extern SECStatus +CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert, + PRBool checkSig, SECCertificateUsage requiredUsages, + void *wincx, SECCertificateUsage* returnedUsages); + +#endif + +PyDoc_STRVAR(Certificate_verify_now_doc, +"verify_now(certdb, check_sig, required_usages) -> valid_usages\n\ +\n\ +:Parameters:\n\ + certdb : CertDB object\n\ + CertDB certificate database object\n\ + check_sig : bool\n\ + True if certificate signatures should be checked\n\ + required_usages : integer\n\ + A bitfield of all cert usages that are required for verification\n\ + to succeed. If zero return all possible valid usages.\n\ +\n\ +Verify a certificate by checking if it's valid and that we\n\ +trust the issuer.\n\ +\n\ +Possible usage bitfield values are:\n\ + - certificateUsageCheckAllUsages\n\ + - certificateUsageSSLClient\n\ + - certificateUsageSSLServer\n\ + - certificateUsageSSLServerWithStepUp\n\ + - certificateUsageSSLCA\n\ + - certificateUsageEmailSigner\n\ + - certificateUsageEmailRecipient\n\ + - certificateUsageObjectSigner\n\ + - certificateUsageUserCertImport\n\ + - certificateUsageVerifyCA\n\ + - certificateUsageProtectedObjectSigner\n\ + - certificateUsageStatusResponder\n\ + - certificateUsageAnyCA\n\ +\n\ +Returns valid_usages, a bitfield of certificate usages. If\n\ +required_usages is non-zero, the returned bitmap is only for those\n\ +required usages, otherwise it is for all possible usages.\n\ +"); + +static PyObject * +Certificate_verify_now(Certificate *self, PyObject *args) +{ + Py_ssize_t argc; + PyObject *pin_args = NULL; + PyObject *py_certdb = NULL; + PyObject *py_check_sig = NULL; + PyObject *py_required_usages = NULL; + int check_sig = 0; + unsigned long required_usages = 0; + SECCertificateUsage returned_usages; + + TraceMethodEnter("verify_now", self); + + argc = PyTuple_Size(args); + if (argc < 3) { + PyErr_Format(PyExc_TypeError, "verify_now: expected at least 3 arguments, but got %jd", (intmax_t)argc); + return NULL; + } + + py_certdb = PyTuple_GetItem(args, 0); + py_check_sig = PyTuple_GetItem(args, 1); + py_required_usages = PyTuple_GetItem(args, 2); + + if (!PyCertDB_Check(py_certdb)) { + PyErr_Format(PyExc_TypeError, "verify_now: certdb parameter must be a %s", CertDBType.tp_name); + return NULL; + } + if (!(PyBool_Check(py_check_sig) || PyInt_Check(py_check_sig))) { + PyErr_SetString(PyExc_TypeError, "verify_now: check_sig parameter must be a boolean or integer"); + return NULL; + } + if (!PyInt_Check(py_required_usages)) { + PyErr_SetString(PyExc_TypeError, "verify_now: required_usages parameter must be an integer"); + return NULL; + } + + pin_args = PyTuple_GetSlice(args, 3, argc); + Py_INCREF(pin_args); + + if (CERT_VerifyCertificateNow(((CertDB *)py_certdb)->handle, self->cert, check_sig, + required_usages, pin_args, &returned_usages) != SECSuccess) { + Py_DECREF(pin_args); + return set_nspr_error(NULL); + } + + Py_DECREF(pin_args); + + return PyInt_FromLong(returned_usages); +} + + +static PyObject * +Certificate_format_lines(Certificate *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + PyObject *obj_lines = NULL; + PyObject *ssl_trust_lines = NULL, *email_trust_lines = NULL, *signing_trust_lines = NULL; + int i; + Py_ssize_t len; + PyObject *tmp_args = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) + goto fail; + + //FMT_LABEL_AND_APPEND(level, "Certificate", lines, fail); + FMT_LABEL_AND_APPEND(level+1, "Data", lines, fail); + + if ((obj = Certificate_get_version(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level+2, "Version", obj, lines, fail); + Py_DECREF(obj); + + if ((obj = Certificate_get_serial_number(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level+2, "Serial Number", obj, lines, fail); + Py_DECREF(obj); + + if ((obj = Certificate_get_signature_algorithm(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level+2, "Signature Algorithm", obj, lines, fail); + Py_DECREF(obj); + + if ((obj = Certificate_get_issuer(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level+2, "Issuer", obj, lines, fail); + Py_DECREF(obj); + + FMT_LABEL_AND_APPEND(level+2, "Validity", lines, fail); + + if ((obj = Certificate_get_valid_not_before_str(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level+3, "Not Before", obj, lines, fail); + Py_DECREF(obj); + + if ((obj = Certificate_get_valid_not_after_str(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level+3, "Not After ", obj, lines, fail); + Py_DECREF(obj); + + if ((obj = Certificate_get_subject(self, NULL)) == NULL) + goto fail; + FMT_OBJ_AND_APPEND(level+2, "Subject", obj, lines, fail); + Py_DECREF(obj); + + FMT_LABEL_AND_APPEND(level+2, "Subject Public Key Info", lines, fail); + + if ((obj = Certificate_get_subject_public_key_info(self, NULL)) == NULL) + goto fail; + if ((tmp_args = Py_BuildValue("(i)", level+3)) == NULL) + goto fail; + if ((obj_lines = SubjectPublicKeyInfo_format_lines((SubjectPublicKeyInfo *)obj, tmp_args, NULL)) == NULL) + goto fail; + Py_DECREF(obj); + Py_DECREF(tmp_args); + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + PyList_Append(lines, obj); + } + Py_DECREF(obj_lines); + + if ((ssl_trust_lines = Certificate_get_ssl_trust_str(self, NULL)) == NULL) + goto fail; + if ((email_trust_lines = Certificate_get_email_trust_str(self, NULL)) == NULL) + goto fail; + if ((signing_trust_lines = Certificate_get_signing_trust_str(self, NULL)) == NULL) + goto fail; + + if ((ssl_trust_lines != Py_None) || (email_trust_lines != Py_None) || (signing_trust_lines != Py_None)) { + FMT_LABEL_AND_APPEND(level+2, "Certificate Trust Flags", lines, fail); + + if (PyList_Check(ssl_trust_lines)) { + FMT_LABEL_AND_APPEND(level+3, "SSL Flags", lines, fail); + len = PyList_Size(ssl_trust_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(ssl_trust_lines, i); + FMT_OBJ_AND_APPEND(level+4, NULL, obj, lines, fail); + } + } + + if (PyList_Check(email_trust_lines)) { + FMT_LABEL_AND_APPEND(level+3, "Email Flags", lines, fail); + len = PyList_Size(email_trust_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(email_trust_lines, i); + FMT_OBJ_AND_APPEND(level+4, NULL, obj, lines, fail); + } + } + + if (PyList_Check(signing_trust_lines)) { + FMT_LABEL_AND_APPEND(level+3, "Object Signing Flags", lines, fail); + len = PyList_Size(signing_trust_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(signing_trust_lines, i); + FMT_OBJ_AND_APPEND(level+4, NULL, obj, lines, fail); + } + } + } + Py_DECREF(ssl_trust_lines); + Py_DECREF(email_trust_lines); + Py_DECREF(signing_trust_lines); + + FMT_LABEL_AND_APPEND(level+2, "Fingerprint (MD5)", lines, fail); + + if ((obj = Certificate_get_der_data(self, NULL)) == NULL) + goto fail; + + if ((tmp_args = Py_BuildValue("(O)", obj)) == NULL) + goto fail; + Py_DECREF(obj); + if ((obj = cert_md5_digest(NULL, tmp_args)) == NULL) + goto fail; + Py_DECREF(tmp_args); + + if ((tmp_args = Py_BuildValue("(O)", obj)) == NULL) + goto fail; + Py_DECREF(obj); + if ((obj_lines = cert_data_to_hex(NULL, tmp_args, NULL)) == NULL) + goto fail; + Py_DECREF(tmp_args); + + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + FMT_OBJ_AND_APPEND(level+3, NULL, obj, lines, fail); + } + Py_DECREF(obj_lines); + + FMT_LABEL_AND_APPEND(level+2, "Fingerprint (SHA1)", lines, fail); + + if ((obj = Certificate_get_der_data(self, NULL)) == NULL) + goto fail; + + if ((tmp_args = Py_BuildValue("(O)", obj)) == NULL) + goto fail; + Py_DECREF(obj); + if ((obj = cert_sha1_digest(NULL, tmp_args)) == NULL) + goto fail; + Py_DECREF(tmp_args); + + if ((tmp_args = Py_BuildValue("(O)", obj)) == NULL) + goto fail; + Py_DECREF(obj); + if ((obj_lines = cert_data_to_hex(NULL, tmp_args, NULL)) == NULL) + goto fail; + Py_DECREF(tmp_args); + + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + FMT_OBJ_AND_APPEND(level+3, NULL, obj, lines, fail); + } + Py_DECREF(obj_lines); + + FMT_LABEL_AND_APPEND(level+1, "Signature", lines, fail); + + if ((obj = Certificate_get_signed_data(self, NULL)) == NULL) + goto fail; + + if ((tmp_args = Py_BuildValue("(i)", level+2)) == NULL) + goto fail; + if ((obj_lines = SignedData_format_lines((SignedData *)obj, tmp_args, NULL)) == NULL) + goto fail; + Py_DECREF(obj); + Py_DECREF(tmp_args); + len = PyList_Size(obj_lines); + for (i = 0; i < len; i++) { + obj = PyList_GET_ITEM(obj_lines, i); + PyList_Append(lines, obj); + } + Py_DECREF(obj_lines); + + return lines; + fail: + Py_XDECREF(obj); + Py_XDECREF(lines); + Py_XDECREF(obj_lines); + Py_XDECREF(tmp_args); + Py_XDECREF(ssl_trust_lines); + Py_XDECREF(email_trust_lines); + Py_XDECREF(signing_trust_lines); + return NULL; +} + +static PyObject * +Certificate_format(Certificate *self, PyObject *args, PyObject *kwds) +{ + return format_from_lines((format_lines_func)Certificate_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +Certificate_str(Certificate *self) +{ + PyObject *py_formatted_result = NULL; + + py_formatted_result = Certificate_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + +static PyMethodDef Certificate_methods[] = { + {"find_kea_type", (PyCFunction)Certificate_find_kea_type, METH_NOARGS, Certificate_find_kea_type_doc}, + {"has_signer_in_ca_names", (PyCFunction)Certificate_has_signer_in_ca_names, METH_VARARGS, Certificate_has_signer_in_ca_names_doc}, + {"verify_hostname", (PyCFunction)Certificate_verify_hostname, METH_VARARGS, Certificate_verify_hostname_doc}, + {"check_valid_times", (PyCFunction)Certificate_check_valid_times, METH_VARARGS, Certificate_check_valid_times_doc}, + {"verify_now", (PyCFunction)Certificate_verify_now, METH_VARARGS, Certificate_verify_now_doc}, + {"format_lines", (PyCFunction)Certificate_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)Certificate_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + // {"", (PyCFunction)Certificate_, METH_RARGS, Certificate__doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +Certificate_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Certificate *self; + + TraceObjNewEnter("Certificate_new", type); + + if ((self = (Certificate *)type->tp_alloc(type, 0)) == NULL) return NULL; + self->cert = NULL; + self->py_subject_public_key_info = NULL; + + TraceObjNewLeave("Certificate_new", self); + return (PyObject *)self; +} + +static void +Certificate_dealloc(Certificate* self) +{ + TraceMethodEnter("Certificate_dealloc", self); + + if (self->cert) + CERT_DestroyCertificate(self->cert); + + Py_XDECREF(self->py_subject_public_key_info); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(Certificate_doc, +"An object representing a Certificate"); + +static int +Certificate_init(Certificate *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("Certificate_init", self); + + return 0; +} + +static PyObject * +Certificate_repr(Certificate *self) +{ + return PyString_FromFormat("<%s object at %p Certificate %p>", + self->ob_type->tp_name, self, self->cert); +} + +static PyTypeObject CertificateType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.Certificate", /* tp_name */ + sizeof(Certificate), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Certificate_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)Certificate_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)Certificate_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Certificate_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Certificate_methods, /* tp_methods */ + Certificate_members, /* tp_members */ + Certificate_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Certificate_init, /* tp_init */ + 0, /* tp_alloc */ + Certificate_new, /* tp_new */ +}; + +PyObject * +Certificate_new_from_cert(CERTCertificate *cert) +{ + Certificate *self = NULL; + + TraceObjNewEnter("Certificate_new_from_cert", NULL); + + if ((self = (Certificate *) CertificateType.tp_new(&CertificateType, NULL, NULL)) == NULL) + return NULL; + + self->cert = cert; + self->py_subject_public_key_info = SubjectPublicKeyInfo_new_from_CERTSubjectPublicKeyInfo(&cert->subjectPublicKeyInfo); + + TraceObjNewLeave("Certificate_new_from_cert", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* ============================= PrivateKey Class =========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static +PyGetSetDef PrivateKey_getseters[] = { + {NULL} /* Sentinel */ +}; + +static PyMemberDef PrivateKey_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + + +static PyMethodDef PrivateKey_methods[] = { + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +PrivateKey_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PrivateKey *self; + + TraceObjNewEnter("PrivateKey_new", type); + + if ((self = (PrivateKey *)type->tp_alloc(type, 0)) == NULL) return NULL; + self->private_key = NULL; + + TraceObjNewLeave("PrivateKey_new", self); + return (PyObject *)self; +} + +static void +PrivateKey_dealloc(PrivateKey* self) +{ + TraceMethodEnter("PrivateKey_dealloc", self); + + if (self->private_key) + SECKEY_DestroyPrivateKey(self->private_key); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(PrivateKey_doc, +"An object representing a Private Key"); + +static int +PrivateKey_init(PrivateKey *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter("PrivateKey_init", self); + return 0; +} + +static PyTypeObject PrivateKeyType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.PrivateKey", /* tp_name */ + sizeof(PrivateKey), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PrivateKey_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + PrivateKey_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PrivateKey_methods, /* tp_methods */ + PrivateKey_members, /* tp_members */ + PrivateKey_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PrivateKey_init, /* tp_init */ + 0, /* tp_alloc */ + PrivateKey_new, /* tp_new */ +}; + +PyObject * +PrivateKey_new_from_private_key(SECKEYPrivateKey *private_key) +{ + PrivateKey *self = NULL; + + TraceObjNewEnter("PrivateKey_new_from_private_key", NULL); + if ((self = (PrivateKey *) PrivateKeyType.tp_new(&PrivateKeyType, NULL, NULL)) == NULL) + return NULL; + + self->private_key = private_key; + + TraceObjNewLeave("PrivateKey_new_from_private_key", self); + return (PyObject *) self; +} + + +/* ============================== Module Methods ============================= */ + +PyDoc_STRVAR(cert_get_default_certdb_doc, +"get_default_certdb()\n\ +\n\ +Returns the default certificate database as a CertDB object\n\ +"); +static PyObject * +cert_get_default_certdb(PyObject *self, PyObject *args) +{ + CERTCertDBHandle *cert_handle; + + if ((cert_handle = CERT_GetDefaultCertDB()) == NULL) + Py_RETURN_NONE; + + return CertDB_new_from_handle(cert_handle); +} + +PyDoc_STRVAR(cert_get_cert_nicknames_doc, +"get_cert_nicknames(certdb, what, [user_data1, ...]) -> name0, ...\n\ +\n\ +:Parameters:\n\ + certdb : CertDB object\n\ + CertDB certificate database object\n\ + what : integer\n\ + one of:\n\ + - SEC_CERT_NICKNAMES_ALL\n\ + - SEC_CERT_NICKNAMES_USER\n\ + - SEC_CERT_NICKNAMES_SERVER\n\ + - SEC_CERT_NICKNAMES_CA\n\ + user_dataN : object\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\n\ +\n\ +Returns a tuple of the nicknames of the certificates in a specified\n\ +certificate database.\n\ +"); + +static PyObject * +cert_get_cert_nicknames(PyObject *self, PyObject *args) +{ + Py_ssize_t argc; + PyObject *pin_args = NULL; + PyObject *py_what = NULL; + int what; + PyObject *py_certdb = NULL; + CERTCertNicknames *cert_nicknames = NULL; + PyObject *py_nicknames = NULL; + PyObject *py_nickname = NULL; + int i, len; + + TraceMethodEnter("cert_get_cert_nicknames", self); + + argc = PyTuple_Size(args); + + if ((py_certdb = PyTuple_GetItem(args, 0)) == NULL) { + PyErr_SetString(PyExc_TypeError, "get_cert_nicknames: missing certdb argument"); + return NULL; + } + if (!PyCertDB_Check(py_certdb)) { + PyErr_Format(PyExc_TypeError, "get_cert_nicknames: certdb parameter must be a %s", CertDBType.tp_name); + return NULL; + } + + if ((py_what = PyTuple_GetItem(args, 1)) == NULL) { + PyErr_SetString(PyExc_TypeError, "get_cert_nicknames: missing what argument"); + return NULL; + } + if (!PyInt_Check(py_what)) { + PyErr_SetString(PyExc_TypeError, "get_cert_nicknames: what parameter must be an int"); + return NULL; + } + what = PyInt_AsLong(py_what); + + pin_args = PyTuple_GetSlice(args, 2, argc); + Py_INCREF(pin_args); + + if ((cert_nicknames = CERT_GetCertNicknames(((CertDB *)py_certdb)->handle, what, pin_args)) == NULL) { + Py_DECREF(pin_args); + return set_nspr_error(NULL); + } + + Py_DECREF(pin_args); + + len = cert_nicknames->numnicknames; + if ((py_nicknames = PyTuple_New(len)) == NULL) { + CERT_FreeNicknames(cert_nicknames); + return NULL; + } + + for (i = 0; i < len; i++) { + if ((py_nickname = PyString_FromString(cert_nicknames->nicknames[i])) == NULL) { + CERT_FreeNicknames(cert_nicknames); + return NULL; + } + PyTuple_SetItem(py_nicknames, i, py_nickname); + } + + CERT_FreeNicknames(cert_nicknames); + + return py_nicknames; +} + +PyDoc_STRVAR(cert_md5_digest_doc, +"md5_digest(data) --> digest\n\ +\n\ +:Parameters:\n\ + data : buffer or string\n\ + buffer the digest will be computed for\n\ +\n\ +Returns 16 octet MD5 digest data as buffer object.\n\ +\n\ +Note, if a hexidecimal string representation is desired then pass\n\ +result to data_to_hex()\n\ +"); + +static PyObject * +cert_md5_digest(PyObject *self, PyObject *args) +{ + PyObject *data_buf = NULL; + unsigned char *raw_data = NULL; + Py_ssize_t raw_data_len = 0; + PK11Context *md5 = NULL; + unsigned char digest[MD5_LENGTH]; + unsigned int digest_len = 0; + + if (!PyArg_ParseTuple(args, "O!:cert_md5_digest", &PyBuffer_Type, &data_buf)) { + return NULL; + } + + if (PyObject_AsReadBuffer(data_buf, (void *)&raw_data, &raw_data_len)) + return NULL; + + if ((md5 = PK11_CreateDigestContext (SEC_OID_MD5)) == NULL) + return set_nspr_error(NULL); + + if (PK11_DigestBegin (md5) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestOp (md5, (unsigned char*)raw_data, raw_data_len) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestFinal (md5, digest, &digest_len, MD5_LENGTH) != SECSuccess) + return set_nspr_error(NULL); + + PK11_DestroyContext (md5, PR_TRUE); + + return data_to_buffer(digest, digest_len); +} + +PyDoc_STRVAR(cert_sha1_digest_doc, +"sha1_digest(data) --> digest\n\ +\n\ +:Parameters:\n\ + data : buffer or string\n\ + buffer the digest will be computed for\n\ +\n\ +Returns 20 octet SHA1 digest data as buffer object.\n\ +\n\ +Note, if a hexidecimal string representation is desired then pass\n\ +result to data_to_hex()\n\ +"); + +static PyObject * +cert_sha1_digest(PyObject *self, PyObject *args) +{ + PyObject *data_buf = NULL; + unsigned char *raw_data = NULL; + Py_ssize_t raw_data_len = 0; + PK11Context *sha1 = NULL; + unsigned char digest[SHA1_LENGTH]; + unsigned int digest_len = 0; + + if (!PyArg_ParseTuple(args, "O!:cert_sha1_digest", &PyBuffer_Type, &data_buf)) { + return NULL; + } + + if (PyObject_AsReadBuffer(data_buf, (void *)&raw_data, &raw_data_len)) + return NULL; + + if ((sha1 = PK11_CreateDigestContext (SEC_OID_SHA1)) == NULL) + return set_nspr_error(NULL); + + if (PK11_DigestBegin (sha1) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestOp (sha1, (unsigned char*)raw_data, raw_data_len) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestFinal (sha1, digest, &digest_len, SHA1_LENGTH) != SECSuccess) + return set_nspr_error(NULL); + + PK11_DestroyContext (sha1, PR_TRUE); + + return data_to_buffer(digest, digest_len); +} + +PyDoc_STRVAR(cert_sha256_digest_doc, +"sha256_digest(data) --> digest\n\ +\n\ +:Parameters:\n\ + data : buffer or string\n\ + buffer the digest will be computed for\n\ +\n\ +Returns 32 octet SHA256 digest data as buffer object.\n\ +\n\ +Note, if a hexidecimal string representation is desired then pass\n\ +result to data_to_hex()\n\ +"); + +static PyObject * +cert_sha256_digest(PyObject *self, PyObject *args) +{ + PyObject *data_buf = NULL; + unsigned char *raw_data = NULL; + Py_ssize_t raw_data_len = 0; + PK11Context *sha256 = NULL; + unsigned char digest[SHA256_LENGTH]; + unsigned int digest_len = 0; + + if (!PyArg_ParseTuple(args, "O!:cert_sha256_digest", &PyBuffer_Type, &data_buf)) { + return NULL; + } + + if (PyObject_AsReadBuffer(data_buf, (void *)&raw_data, &raw_data_len)) + return NULL; + + if ((sha256 = PK11_CreateDigestContext (SEC_OID_SHA256)) == NULL) + return set_nspr_error(NULL); + + if (PK11_DigestBegin (sha256) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestOp (sha256, (unsigned char*)raw_data, raw_data_len) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestFinal (sha256, digest, &digest_len, SHA256_LENGTH) != SECSuccess) + return set_nspr_error(NULL); + + PK11_DestroyContext (sha256, PR_TRUE); + + return data_to_buffer(digest, digest_len); +} + +PyDoc_STRVAR(cert_sha512_digest_doc, +"sha512_digest(data) --> digest\n\ +\n\ +:Parameters:\n\ + data : buffer or string\n\ + buffer the digest will be computed for\n\ +\n\ +Returns 64 octet SHA512 digest data as buffer object.\n\ +\n\ +Note, if a hexidecimal string representation is desired then pass\n\ +result to data_to_hex()\n\ +"); + +static PyObject * +cert_sha512_digest(PyObject *self, PyObject *args) +{ + PyObject *data_buf = NULL; + unsigned char *raw_data = NULL; + Py_ssize_t raw_data_len = 0; + PK11Context *sha512 = NULL; + unsigned char digest[SHA512_LENGTH]; + unsigned int digest_len = 0; + + if (!PyArg_ParseTuple(args, "O!:cert_sha512_digest", &PyBuffer_Type, &data_buf)) { + return NULL; + } + + if (PyObject_AsReadBuffer(data_buf, (void *)&raw_data, &raw_data_len)) + return NULL; + + if ((sha512 = PK11_CreateDigestContext (SEC_OID_SHA512)) == NULL) + return set_nspr_error(NULL); + + if (PK11_DigestBegin (sha512) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestOp (sha512, (unsigned char*)raw_data, raw_data_len) != SECSuccess) + return set_nspr_error(NULL); + + if (PK11_DigestFinal (sha512, digest, &digest_len, SHA512_LENGTH) != SECSuccess) + return set_nspr_error(NULL); + + PK11_DestroyContext (sha512, PR_TRUE); + + return data_to_buffer(digest, digest_len); +} + +/* ========================================================================== */ +/* ============================== PK11Slot Class ============================ */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +PK11_get_slot_name(PK11Slot *self, void *closure) +{ + char *slot_name = NULL; + + if ((slot_name = PK11_GetSlotName(self->slot)) == NULL) + Py_RETURN_NONE; + + return PyString_FromString(slot_name); +} + +static PyObject * +PK11_get_token_name(PK11Slot *self, void *closure) +{ + char *token_name = NULL; + + if ((token_name = PK11_GetTokenName(self->slot)) == NULL) + Py_RETURN_NONE; + + return PyString_FromString(token_name); +} + +static +PyGetSetDef PK11Slot_getseters[] = { + {"slot_name", (getter)PK11_get_slot_name, (setter)NULL, "slot name", NULL}, + {"token_name", (getter)PK11_get_token_name, (setter)NULL, "token name", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef PK11Slot_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +PyDoc_STRVAR(PK11Slot_is_hw_doc, +"is_hw() -> bool\n\ +\n\ +Finds out whether a slot is implemented in hardware or software.\n\ +"); +static PyObject * +PK11Slot_is_hw(PK11Slot *self, PyObject *args, PyObject *kwds) +{ + if (PK11_IsHW(self->slot)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +PyDoc_STRVAR(PK11Slot_is_present_doc, +"is_present() -> bool\n\ +\n\ +Finds out whether the token for a slot is available.\n\ +"); +static PyObject * +PK11Slot_is_present(PK11Slot *self, PyObject *args, PyObject *kwds) +{ + if (PK11_IsPresent(self->slot)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +PyDoc_STRVAR(PK11Slot_is_read_only_doc, +"is_read_only() -> bool\n\ +\n\ +Finds out whether a slot is read-only.\n\ +"); +static PyObject * +PK11Slot_is_read_only(PK11Slot *self, PyObject *args, PyObject *kwds) +{ + if (PK11_IsReadOnly(self->slot)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; + +} + +static PyMethodDef PK11Slot_methods[] = { + {"is_hw", (PyCFunction)PK11Slot_is_hw, METH_NOARGS, PK11Slot_is_hw_doc}, + {"is_present", (PyCFunction)PK11Slot_is_present, METH_NOARGS, PK11Slot_is_present_doc}, + {"is_read_only", (PyCFunction)PK11Slot_is_read_only, METH_NOARGS, PK11Slot_is_read_only_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +PK11Slot_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PK11Slot *self; + + TraceObjNewEnter("PK11Slot_new", type); + + if ((self = (PK11Slot *)type->tp_alloc(type, 0)) == NULL) return NULL; + self->slot = NULL; + + TraceObjNewLeave("PK11Slot_new", type); + return (PyObject *)self; +} + +static void +PK11Slot_dealloc(PK11Slot* self) +{ + TraceMethodEnter("PK11Slot_dealloc", self); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(PK11Slot_doc, +"An object representing a PKCS #11 Slot"); + +static int +PK11Slot_init(PK11Slot *self, PyObject *args, PyObject *kwds) +{ + PyObject *arg1 = NULL; + static char *kwlist[] = {"arg1", NULL}; + + TraceMethodEnter("PK11Slot_init", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, + &arg1)) + return -1; + + return 0; +} + +static PyTypeObject PK11SlotType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.PK11Slot", /* tp_name */ + sizeof(PK11Slot), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PK11Slot_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + PK11Slot_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PK11Slot_methods, /* tp_methods */ + PK11Slot_members, /* tp_members */ + PK11Slot_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PK11Slot_init, /* tp_init */ + 0, /* tp_alloc */ + PK11Slot_new, /* tp_new */ +}; + +PyObject * +PK11Slot_new_from_slotinfo(PK11SlotInfo *slot) +{ + PK11Slot *self = NULL; + + TraceObjNewEnter("PK11Slot_new_from_slotinfo", NULL); + + if ((self = (PK11Slot *) PK11SlotType.tp_new(&PK11SlotType, NULL, NULL)) == NULL) + return NULL; + + self->slot = slot; + TraceObjNewLeave("PK11Slot_new_from_slotinfo", self); + return (PyObject *) self; +} + +static PyObject *password_callback = NULL; + +static char * +PK11_password_callback(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + PyObject *pin_args = arg; /* borrowed reference, don't decrement */ + PyObject *py_retry = NULL; + PyObject *py_slot = NULL; + PyObject *item; + PyObject *result = NULL; + PyObject *new_args = arg; + Py_ssize_t argc; + int i, j; + char *password = NULL; + + TraceMessage("PK11_password_callback: enter"); + + if (password_callback == NULL) { + PySys_WriteStderr("PK11 password callback undefined\n"); + return NULL;; + } + + argc = 2; + if (pin_args) { + if (PyTuple_Check(pin_args)) { + argc += PyTuple_Size(pin_args); + } else { + PySys_WriteStderr("Error, PK11 password callback expected args to be tuple\n"); + PyErr_Print(); + } + } + + if ((new_args = PyTuple_New(argc)) == NULL) { + PySys_WriteStderr("PK11 password callback: out of memory\n"); + goto exit; + } + + py_retry = PyBool_FromLong(retry); + Py_INCREF(py_retry); + + if ((py_slot = PK11Slot_new_from_slotinfo(slot)) == NULL) { + PySys_WriteStderr("exception in PK11 password callback\n"); + PyErr_Print(); + goto exit; + return NULL;; + } + + PyTuple_SetItem(new_args, 0, py_slot); + PyTuple_SetItem(new_args, 1, py_retry); + + for (i = 2, j = 0; i < argc; i++, j++) { + item = PyTuple_GetItem(pin_args, j); + Py_INCREF(item); + PyTuple_SetItem(new_args, i, item); + } + + if ((result = PyObject_CallObject(password_callback, new_args)) == NULL) { + PySys_WriteStderr("exception in PK11 password callback\n"); + PyErr_Print(); /* this also clears the error */ + goto exit; + } + + if (!PyString_Check(result)) { + PySys_WriteStderr("Error, PK11 password callback expected string result.\n"); + goto exit; + } + + password = PyString_AsString(result); + + exit: + TraceMessage("PK11_password_callback: exiting"); + + Py_XDECREF(new_args); + //FIXME Py_XDECREF(py_retry); + //FIXME Py_XDECREF(py_slot); + Py_XDECREF(result); + + if (password) + return PORT_Strdup(password); + else + return NULL; +} + +/* ========================== PK11 Module Methods =========================== */ + +PyDoc_STRVAR(PK11_set_password_callback_doc, +"set_password_callback(callback)\n\ +\n\ +:Parameters:\n\ + callback : function pointer\n\ + The callback function\n\ + \n\ +The callback has the signature::\n\ + \n\ + password_callback(slot, retry, [user_data1, ...])\n\ +\n\ +slot\n\ + PK11Slot object\n\ +retry\n\ + boolean indicating if this is a retry\n\ +user_dataN\n\ + zero or more caller supplied optional parameters\n\ +"); + +static PyObject * +PK11_set_password_callback(PyObject *self, PyObject *args) +{ + PyObject *callback; + + TraceMethodEnter("PK11_set_password_callback", self); + + if (!PyArg_ParseTuple(args, "O:set_password_callback", &callback)) { + return NULL; + } + + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "callback must be callable"); + return NULL; + } + + Py_XDECREF(password_callback); + password_callback = callback; + Py_INCREF(callback); + + PK11_SetPasswordFunc(PK11_password_callback); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(PK11_find_cert_from_nickname_doc, +"find_cert_from_nickname(nickname, [user_data1, ...]) -> Certificate\n\ +\n\ +:Parameters:\n\ + nickname : string\n\ + certificate nickname to search for\n\ + user_dataN : object ...\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\n\ +\n\ +A nickname is an alias for a certificate subject. There may be\n\ +multiple certificates with the same subject, and hence the same\n\ +nickname. This function will return the newest certificate that\n\ +matches the subject, based on the NotBefore / NotAfter fields of the\n\ +certificate.\n\ +"); + +static PyObject * +PK11_find_cert_from_nickname(PyObject *self, PyObject *args) +{ + PyObject *py_nickname = NULL; + char *nickname = NULL; + Py_ssize_t argc; + PyObject *pin_args = NULL; + CERTCertificate *cert = NULL; + PyObject *py_cert = NULL; + + TraceMethodEnter("PK11_find_cert_from_nickname", self); + + argc = PyTuple_Size(args); + + if ((py_nickname = PyTuple_GetItem(args, 0)) == NULL) { + PyErr_SetString(PyExc_TypeError, "find_cert_from_nickname: missing nickname argument"); + return NULL; + } + + if (!PyString_Check(py_nickname)) { + PyErr_SetString(PyExc_TypeError, "find_cert_from_nickname: nickname parameter must be a string"); + return NULL; + } + + nickname = PyString_AsString(py_nickname); + pin_args = PyTuple_GetSlice(args, 1, argc); + Py_INCREF(pin_args); + + if ((cert = PK11_FindCertFromNickname(nickname, pin_args)) == NULL) { + Py_DECREF(pin_args); + return set_nspr_error(NULL); + } + + Py_DECREF(pin_args); + + if ((py_cert = Certificate_new_from_cert(cert)) == NULL) { + return NULL; + } + + return py_cert; +} + +PyDoc_STRVAR(PK11_find_key_by_any_cert_doc, +"find_key_by_any_cert(cert, [user_data1, ...]) -> Certificate\n\ +\n\ +:Parameters:\n\ + cert : Certificate object\n\ + certificate whose private key is being searched for\n\ + user_dataN : object ...\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\n\ +\n\ +Finds the private key associated with a specified certificate in any\n\ +available slot.\n\ +"); + +static PyObject * +PK11_find_key_by_any_cert(PyObject *self, PyObject *args) +{ + PyObject *py_cert = NULL; + Py_ssize_t argc; + PyObject *pin_args = NULL; + SECKEYPrivateKey *private_key; + PyObject *py_private_key = NULL; + + TraceMethodEnter("PK11_find_key_by_any_cert", self); + + argc = PyTuple_Size(args); + + if ((py_cert = PyTuple_GetItem(args, 0)) == NULL) { + PyErr_SetString(PyExc_TypeError, "find_key_by_any_cert: missing cert argument"); + return NULL; + } + + if (!PyCertificate_Check(py_cert)) { + PyErr_Format(PyExc_TypeError, "find_key_by_any_cert: cert parameter must be a %s", CertificateType.tp_name); + return NULL; + } + + pin_args = PyTuple_GetSlice(args, 1, argc); + Py_INCREF(pin_args); + + if ((private_key = PK11_FindKeyByAnyCert(((Certificate *)py_cert)->cert, pin_args)) == NULL) { + Py_DECREF(pin_args); + return set_nspr_error(NULL); + } + + Py_DECREF(pin_args); + + if ((py_private_key = PrivateKey_new_from_private_key(private_key)) == NULL) { + return NULL; + } + + return py_private_key; +} + +PyDoc_STRVAR(PK11_generate_random_doc, +"generate_random(num_bytes) -> string\n\ +\n\ +:Parameters:\n\ + num_bytes : integer\n\ + Number of num_bytes to generate (must be non-negative)\n\ +\n\ +Generates random data..\n\ +"); + +static PyObject * +PK11_generate_random(PyObject *self, PyObject *args) +{ + int num_bytes; + unsigned char *buf; + SECStatus status; + PyObject *res; + + TraceMethodEnter("PK11_generate_random", self); + + if (!PyArg_ParseTuple(args, "i:generate_random", &num_bytes)) + return NULL; + + if (num_bytes < 0) { + PyErr_SetString(PyExc_ValueError, "byte count must be non-negative"); + return NULL; + } + + buf = PyMem_Malloc(num_bytes); + if (buf == NULL) + return PyErr_NoMemory(); + + status = PK11_GenerateRandom(buf, num_bytes); + if (status != SECSuccess) { + PyMem_Free(buf); + return set_nspr_error(NULL); + } + + res = PyString_FromStringAndSize((char *)buf, num_bytes); + PyMem_Free(buf); + return res; +} + +PyDoc_STRVAR(cert_data_to_hex_doc, +"data_to_hex(data, octets_per_line=16, separator=\":\")\n\ +\n\ +:Parameters:\n\ + data : buffer\n\ + binary data\n\ + octets_per_line : integer\n\ + number of octets formatted on one line, if 0 then\n\ + return a single string instead of an array of lines\n\ + separator : string\n\ + string used to seperate each octet\n\ +\n\ +Format the binary data as a hex string. If octets_per_line is an integer then return a list of lines\n\ +otherwise return a single string\n\ +"); + +PyDoc_STRVAR(nss_indented_format_doc, +"indented_format(line_pairs, indent=' ') -> string\n\ +\n\ +:Parameters:\n\ + line_pairs : [(level, string),...]\n\ + A list of pairs. Each pair is a 2 valued tuple with the first pair\n\ + value being the indentation level and the second pair value being\n\ + a string value for the line.\n\ + indent : string\n\ + A string repeated level times and then prepended to the line string.\n\ +\n\ +This function is equivalent to::\n\ +\n\ +'\\n'.join([indent*x[0]+x[1] for x in obj.format()])\n\ +\n\ +But is more efficient and does more error checking.\n\ +\n\ +Example::\n\ + \n\ + format = [(0, 'line 1'), (1, 'line 2'), (0, 'line 3')]\n\ + nss.indented(format)\n\ +\n\ + would print\n\ + line 1\n\ + line 2\n\ + line 3\n\ +"); + +static PyObject * +nss_indented_format(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"lines", "indent", NULL}; + PyObject *py_lines = NULL; + PyObject *py_indent = NULL; + long line_level = 0; + long cur_level = -1; + PyObject *py_cur_level_indent = NULL; + char *indent = NULL; + Py_ssize_t indent_len = 0; + long cur_indent_len = 0; + char *indent_end = NULL; + char *src=NULL, *dst=NULL; + Py_ssize_t num_lines; + char *line = NULL; + Py_ssize_t line_len; + char *line_end = NULL; + PyObject *py_pair = NULL; + PyObject *py_level; + PyObject *py_line; + Py_ssize_t cur_formatted_line_len; + PyObject *py_formatted_str = NULL; + Py_ssize_t formatted_str_len; + char *formatted_str; + long i; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|S:indented_format", kwlist, + &PyList_Type, &py_lines, &py_indent)) + return NULL; + + if (!py_indent) { + if ((py_indent = PyString_FromString(" ")) == NULL) + goto fail; + } else { + Py_INCREF(py_indent); + } + + indent_len = PyString_Size(py_indent); + formatted_str_len = 0; + + num_lines = PyList_Size(py_lines); + + /* First, scan all the lines and compute the final destination size, do all error in this + loop so we don't have to do it again during the copy phase */ + for (i = 0; i < num_lines; i++) { + py_pair = PyList_GET_ITEM(py_lines, i); + if (!PyTuple_Check(py_pair) || PyTuple_Size(py_pair) != 2) { + PyErr_Format(PyExc_TypeError, "lines[%ld] must be a 2 valued tuple", i); + goto fail; + } + + py_level = PyTuple_GET_ITEM(py_pair, 0); + py_line = PyTuple_GET_ITEM(py_pair, 1); + + if (!PyInt_Check(py_level)) { + PyErr_Format(PyExc_TypeError, "the first item in the pair at lines[%ld] list must be an integer", i); + goto fail; + } + line_level = PyInt_AsLong(py_level); + if (line_level < 0) { + PyErr_Format(PyExc_TypeError, "the first item in the pair at lines[%ld] list must be a non-negative integer", i); + goto fail; + } + + if (!PyString_Check(py_line)) { + PyErr_Format(PyExc_TypeError, "the second item in the pair at lines[%ld] list must be a string", i); + goto fail; + } + if (PyString_AsStringAndSize(py_line, &line, &line_len) == -1) + goto fail; + + cur_indent_len = line_level * indent_len; + cur_formatted_line_len = cur_indent_len + line_len + 1; /* +1 for newline */ + formatted_str_len += cur_formatted_line_len; + } + + /* Now copy the strings into the destination, note all error checking has been done above */ + if (num_lines > 0) formatted_str_len -= 1; /* last line doesn't get a new line appended */ + if ((py_formatted_str = PyString_FromStringAndSize(NULL, formatted_str_len)) == NULL) + goto fail; + + formatted_str = PyString_AsString(py_formatted_str); + dst = formatted_str; + + for (i = 0; i < num_lines; i++) { + py_pair = PyList_GET_ITEM(py_lines, i); + py_level = PyTuple_GET_ITEM(py_pair, 0); + py_line = PyTuple_GET_ITEM(py_pair, 1); + + line_level = PyInt_AsLong(py_level); + PyString_AsStringAndSize(py_line, &line, &line_len); + line_end = line + line_len; + + if (line_level != cur_level) { + cur_level = line_level; + if ((py_cur_level_indent = PySequence_Repeat(py_indent, cur_level)) == NULL) { + goto fail; + } + if (PyString_AsStringAndSize(py_cur_level_indent, &indent, &indent_len) == -1) + goto fail; + indent_end = indent + indent_len; + } + + for (src = indent; src < indent_end; *dst++ = *src++); + for (src = line; src < line_end; *dst++ = *src++); + if (i < num_lines-1) + *dst++ = '\n'; + } + + assert(formatted_str + PyString_Size(py_formatted_str) == dst); + Py_DECREF(py_indent); + Py_XDECREF(py_cur_level_indent); + return py_formatted_str; + + fail: + Py_XDECREF(py_indent); + Py_XDECREF(py_cur_level_indent); + Py_XDECREF(py_formatted_str); + return NULL; +} + + + +/* List of functions exported by this module. */ +static PyMethodDef +module_methods[] = { + {"set_password_callback", PK11_set_password_callback, METH_VARARGS, PK11_set_password_callback_doc}, + {"find_cert_from_nickname", PK11_find_cert_from_nickname, METH_VARARGS, PK11_find_cert_from_nickname_doc}, + {"find_key_by_any_cert", PK11_find_key_by_any_cert, METH_VARARGS, PK11_find_key_by_any_cert_doc}, + {"generate_random", PK11_generate_random, METH_VARARGS, PK11_generate_random_doc}, + {"get_default_certdb", cert_get_default_certdb, METH_NOARGS, cert_get_default_certdb_doc}, + {"get_cert_nicknames", cert_get_cert_nicknames, METH_VARARGS, cert_get_cert_nicknames_doc}, + {"data_to_hex", (PyCFunction)cert_data_to_hex, METH_VARARGS|METH_KEYWORDS, cert_data_to_hex_doc}, + {"md5_digest", (PyCFunction)cert_md5_digest, METH_VARARGS, cert_md5_digest_doc}, + {"sha1_digest", (PyCFunction)cert_sha1_digest, METH_VARARGS, cert_sha1_digest_doc}, + {"sha256_digest", (PyCFunction)cert_sha256_digest, METH_VARARGS, cert_sha256_digest_doc}, + {"sha512_digest", (PyCFunction)cert_sha512_digest, METH_VARARGS, cert_sha512_digest_doc}, + {"indented_format", (PyCFunction)nss_indented_format,METH_VARARGS|METH_KEYWORDS, nss_indented_format_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* ============================== Module Exports ============================= */ + +static PyNSPR_NSS_C_API_Type nspr_nss_c_api = +{ + &PK11SlotType, + &CertDBType, + &CertificateType, + &PrivateKeyType, + &SecItemType, + Certificate_new_from_cert, + PrivateKey_new_from_private_key, + SecItem_new_from_sec_item, + cert_distnames_new_from_CERTDistNames, + cert_distnames_as_CERTDistNames +}; + +/* ============================== Module Construction ============================= */ + +#define TYPE_READY(type) \ +{ \ + if (PyType_Ready(&type) < 0) \ + return; \ + Py_INCREF(&type); \ + PyModule_AddObject(m, rindex(type.tp_name, '.')+1, (PyObject *)&type); \ +} + +PyDoc_STRVAR(module_doc, +"This module implements the NSS functions\n\ +\n\ +"); + +PyMODINIT_FUNC +initnss(void) +{ + PyObject *m; + + if (import_nspr_error_c_api() < 0) + return; + + if ((m = Py_InitModule3("nss.nss", module_methods, module_doc)) == NULL) + return; + + if ((empty_tuple = PyTuple_New(0)) == NULL) + return; + Py_INCREF(empty_tuple); + + TYPE_READY(SecItemType); + TYPE_READY(SignatureAlgorithmType); + TYPE_READY(KEYPQGParamsType); + TYPE_READY(RSAPublicKeyType); + TYPE_READY(DSAPublicKeyType); + TYPE_READY(SignedDataType); + TYPE_READY(PublicKeyType); + TYPE_READY(SubjectPublicKeyInfoType); + TYPE_READY(CertDBType); + TYPE_READY(CertificateType); + TYPE_READY(PrivateKeyType); + TYPE_READY(PK11SlotType); + + /* Export C API */ + if (PyModule_AddObject(m, "_C_API", PyCObject_FromVoidPtr((void *)&nspr_nss_c_api, NULL)) != 0) + return; + + AddIntConstant(certificateUsageCheckAllUsages); + AddIntConstant(certificateUsageSSLClient); + AddIntConstant(certificateUsageSSLServer); + AddIntConstant(certificateUsageSSLServerWithStepUp); + AddIntConstant(certificateUsageSSLCA); + AddIntConstant(certificateUsageEmailSigner); + AddIntConstant(certificateUsageEmailRecipient); + AddIntConstant(certificateUsageObjectSigner); + AddIntConstant(certificateUsageUserCertImport); + AddIntConstant(certificateUsageVerifyCA); + AddIntConstant(certificateUsageProtectedObjectSigner); + AddIntConstant(certificateUsageStatusResponder); + AddIntConstant(certificateUsageAnyCA); + + AddIntConstant(ssl_kea_null); + AddIntConstant(ssl_kea_rsa); + AddIntConstant(ssl_kea_dh); + AddIntConstant(ssl_kea_fortezza); + AddIntConstant(ssl_kea_ecdh); + + AddIntConstant(nullKey); + AddIntConstant(rsaKey); + AddIntConstant(dsaKey); + AddIntConstant(fortezzaKey); + AddIntConstant(dhKey); + AddIntConstant(keaKey); + AddIntConstant(ecKey); + + AddIntConstant(SEC_CERT_NICKNAMES_ALL); + AddIntConstant(SEC_CERT_NICKNAMES_USER); + AddIntConstant(SEC_CERT_NICKNAMES_SERVER); + AddIntConstant(SEC_CERT_NICKNAMES_CA); + + AddIntConstant(secCertTimeValid); + AddIntConstant(secCertTimeExpired); + AddIntConstant(secCertTimeNotValidYet); + + +} diff --git a/mozilla/security/python/nss/src/py_nss.h b/mozilla/security/python/nss/src/py_nss.h new file mode 100644 index 00000000000..b1bac6232e0 --- /dev/null +++ b/mozilla/security/python/nss/src/py_nss.h @@ -0,0 +1,267 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// FIXME: some of these class types have items in them with arenas, but we can't hold a reference +// to an arena, so check to make sure we copy the items out and don't store the +// the item with the arena in it. + +/* NSPR header files */ +#undef HAVE_LONG_LONG /* FIXME: both Python.h and nspr.h define HAVE_LONG_LONG */ +#include "nspr.h" +#include "cert.h" +#include "nss.h" +#include "ssl.h" +#include "sslt.h" +#include "key.h" +#include "pk11pub.h" + +/* ========================================================================== */ +/* =============================== PK11Slot Class =========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PK11SlotInfo *slot; +} PK11Slot; + +/* ========================================================================== */ +/* ================================ CertDB Class ============================ */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + CERTCertDBHandle *handle; +} CertDB; + + +/* ========================================================================== */ +/* ============================ Certificate Class =========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + CERTCertificate *cert; + PyObject *py_subject_public_key_info; +} Certificate; + + +/* ========================================================================== */ +/* ============================= PrivateKey Class =========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + SECKEYPrivateKey *private_key; +} PrivateKey; + +/* ========================================================================== */ +/* =============================== SecItem Class ============================ */ +/* ========================================================================== */ + +typedef enum SECItemKindEnum { + SECITEM_unknown, + SECITEM_dist_name, + SECITEM_session_id, + SECITEM_signed_data, + SECITEM_signature, + SECITEM_algorithm, +} SECItemKind; + +typedef struct { + PyObject_HEAD + SECItem item; + SECItemKind kind; +} SecItem; + +/* ========================================================================== */ +/* ============================ RSAPublicKey Class ========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PyObject *py_modulus; + PyObject *py_exponent; +} RSAPublicKey; + +/* ========================================================================== */ +/* ============================ DSAPublicKey Class ========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PyObject *py_pqg_params; + PyObject *py_public_value; +} DSAPublicKey; + +/* ========================================================================== */ +/* ============================ KEYPQGParams Class ========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PyObject *py_prime; + PyObject *py_subprime; + PyObject *py_base; +} KEYPQGParams; + +/* ========================================================================== */ +/* ======================== SignatureAlgorithm Class ======================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + SECAlgorithmID id; + PyObject *py_id; + PyObject *py_parameters; +} SignatureAlgorithm; + +/* ========================================================================== */ +/* ============================= SignedData Class =========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PRArenaPool *arena; + CERTSignedData signed_data; + PyObject *py_data; + PyObject *py_algorithm; + PyObject *py_signature; +} SignedData; + +/* ========================================================================== */ +/* ============================= PublicKey Class =========================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + SECKEYPublicKey *pk; + PyObject *py_pk11slot; + PyObject *py_rsa_key; + PyObject *py_dsa_key; +} PublicKey; + +/* ========================================================================== */ +/* ======================== SubjectPublicKeyInfo Class ====================== */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + PRArenaPool *arena; + CERTSubjectPublicKeyInfo spki; + PyObject *py_algorithm; + PyObject *py_public_key; +} SubjectPublicKeyInfo; + +typedef struct { + PyTypeObject *pk11slot_type; + PyTypeObject *certdb_type; + PyTypeObject *certificate_type; + PyTypeObject *private_key_type; + PyTypeObject *sec_item_type; + PyObject *(*Certificate_new_from_cert)(CERTCertificate *cert); + PyObject *(*PrivateKey_new_from_private_key)(SECKEYPrivateKey *private_key); + PyObject *(*SecItem_new_from_sec_item)(SECItem *item, SECItemKind type); + PyObject *(*cert_distnames_new_from_CERTDistNames)(CERTDistNames *names); + CERTDistNames *(*cert_distnames_as_CERTDistNames)(PyObject *py_distnames); +} PyNSPR_NSS_C_API_Type; + +#ifdef NSPR_NSS_MODULE + +#define PyPK11Slot_Check(op) PyObject_TypeCheck(op, &PK11SlotType) +#define PyCertDB_Check(op) PyObject_TypeCheck(op, &CertDBType) +#define PyCertificate_Check(op) PyObject_TypeCheck(op, &CertificateType) +#define PyPrivateKey_Check(op) PyObject_TypeCheck(op, &PrivateKeyType) +#define PySecItem_Check(op) PyObject_TypeCheck(op, &SecItemType) + +PyObject * +PK11Slot_new_from_slotinfo(PK11SlotInfo *slot); + +#else /* not NSPR_NSS_MODULE */ + +#define CertDBType (*nspr_nss_c_api.certdb_type) +#define CertificateType (*nspr_nss_c_api.certificate_type) +#define PrivateKeyType (*nspr_nss_c_api.private_key_type) +#define SecItemType (*nspr_nss_c_api.sec_item_type) + +#define PyPK11Slot_Check(op) PyObject_TypeCheck(op, nspr_nss_c_api.pk11slot_type) +#define PyCertDB_Check(op) PyObject_TypeCheck(op, nspr_nss_c_api.certdb_type) +#define PyCertificate_Check(op) PyObject_TypeCheck(op, nspr_nss_c_api.certificate_type) +#define PyPrivateKey_Check(op) PyObject_TypeCheck(op, nspr_nss_c_api.private_key_type) +#define PySecItem_Check(op) PyObject_TypeCheck(op, nspr_nss_c_api.sec_item_type) + +static PyNSPR_NSS_C_API_Type nspr_nss_c_api; + +#define Certificate_new_from_cert (*nspr_nss_c_api.Certificate_new_from_cert) +#define PrivateKey_new_from_private_key (*nspr_nss_c_api.PrivateKey_new_from_private_key) +#define SecItem_new_from_sec_item (*nspr_nss_c_api.SecItem_new_from_sec_item) +#define cert_distnames_new_from_CERTDistNames (*nspr_nss_c_api.cert_distnames_new_from_CERTDistNames) +#define cert_distnames_as_CERTDistNames (*nspr_nss_c_api.cert_distnames_as_CERTDistNames) + +static int +import_nspr_nss_c_api(void) +{ + PyObject *module = NULL; + PyObject *c_api_object = NULL; + void *api = NULL; + + if ((module = PyImport_ImportModule("nss.nss")) == NULL) + return -1; + + if ((c_api_object = PyObject_GetAttrString(module, "_C_API")) == NULL) { + Py_DECREF(module); + return -1; + } + + if (!(PyCObject_Check(c_api_object))) { + Py_DECREF(c_api_object); + Py_DECREF(module); + return -1; + } + + if ((api = PyCObject_AsVoidPtr(c_api_object)) == NULL) { + Py_DECREF(c_api_object); + Py_DECREF(module); + return -1; + } + + memcpy(&nspr_nss_c_api, api, sizeof(nspr_nss_c_api)); + Py_DECREF(c_api_object); + Py_DECREF(module); + return 0; +} + +#endif /* NSPR_NSS_MODULE */ diff --git a/mozilla/security/python/nss/src/py_ssl.c b/mozilla/security/python/nss/src/py_ssl.c new file mode 100644 index 00000000000..40fed9cdbe1 --- /dev/null +++ b/mozilla/security/python/nss/src/py_ssl.c @@ -0,0 +1,2349 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// FIXME: sometimes in the API dist_name is used and sometimes ca_name, make consistent. +// FIXME: PyIntObjects represent their value as a long, but in many places we declared their C representation as +// as int, we should change it to long, and at the same time match the parameters used in the NSPR/NSS API + +#include "Python.h" +#include "structmember.h" + +#include "py_nspr_common.h" +#include "py_nspr_io.h" +#include "py_ssl.h" +#include "py_nss.h" +#include "py_nspr_error.h" + +#include "sslproto.h" /* for cipher constants */ + +static PyObject *py_ssl_implemented_ciphers = NULL; + +// FIXME: this should be imported from socket module +static PyObject * +NetworkAddress_new_from_prnetaddr(PRNetAddr *pr_netaddr) +{ + NetworkAddress *self = NULL; + + TraceObjNewEnter("NetworkAddress_new_from_prnetaddr", NULL); + + if ((self = (NetworkAddress *) NetworkAddressType.tp_new(&NetworkAddressType, NULL, NULL)) == NULL) + return NULL; + + self->addr = *pr_netaddr; + + TraceObjNewLeave("NetworkAddress_new_from_prnetaddr", self); + return (PyObject *) self; +} + +static PyObject * +SSLSocket_new_from_prfiledesc(PRFileDesc *pr_socket, int family) +{ + SSLSocket *self = NULL; + + TraceObjNewEnter("SSLSocket_new_from_prfiledesc", NULL); + + if ((self = (SSLSocket *) SSLSocketType.tp_new(&SSLSocketType, NULL, NULL)) == NULL) + return NULL; + + Socket_init_from_prfiledesc((Socket *)self, pr_socket, family); + + TraceObjNewLeave("SSLSocket_new_from_prfiledesc", self); + return (PyObject *) self; +} + +/* ========================================================================== */ +/* ============================= SSLSocket Class ============================ */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyGetSetDef +SSLSocket_getseters[] = { + {NULL} /* Sentinel */ +}; + +static PyMemberDef +SSLSocket_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +PyDoc_STRVAR(SSLSocket_set_ssl_option_doc, +"set_ssl_option(option, value)\n\ +\n\ +Sets a single configuration parameter on this socket. Call once for\n\ +each parameter you want to change. The configuration parameters are\n\ +listed below.\n\ +\n\ +SSL_SECURITY (default=True)\n\ + Enables use of security protocol. *WARNING: If you turn this option\n\ + off, the session will not be an SSL session and will not have\n\ + certificate-based authentication, tamper detection, or encryption.*\n\ +SSL_REQUEST_CERTIFICATE: (default=False)\n\ + Is a server option that requests a client to authenticate itself.\n\ +SSL_REQUIRE_CERTIFICATE: (default=SSL_REQUIRE_FIRST_HANDSHAKE)\n\ + Is a server option that requires a client to authenticate itself (only\n\ + if SSL_REQUEST_CERTIFICATE is also on). If client does not provide\n\ + certificate, the connection terminates.\n\ +SSL_HANDSHAKE_AS_CLIENT: (default=False)\n\ + Controls the behavior of SSLSocket.accept(),. If this option is off,\n\ + the SSLSocket.accept() configures the SSL socket to handshake as a\n\ + server. If it is on, then SSLSocket.accept() configures the SSL socket\n\ + to handshake as a client, even though it accepted the connection as a\n\ + TCP server.\n\ +SSL_HANDSHAKE_AS_SERVER: (default=False)\n\ + Controls the behavior of SSLSocket.connect(). If this option is off,\n\ + then SSLSocket.connect() configures the SSL socket to handshake as a\n\ + client. If it is on, then SSLSocket.connect() configures the SSL\n\ + socket to handshake as a server, even though it connected as a TCP\n\ + client.\n\ +SSL_ENABLE_FDX: (default=False)\n\ + Tells the SSL library whether the application will have two threads,\n\ + one reading and one writing, or just one thread doing reads and writes\n\ + alternately. The factory setting for this option (which is the\n\ + default, unless the application changes the default) is off, which\n\ + means that the application will not do simultaneous reads and\n\ + writes. An application that needs to do simultaneous reads and writes\n\ + should set this to True.\n\ +\n\ + In NSS 2.8, the SSL_ENABLE_FDX option only affects the behavior of\n\ + nonblocking SSL sockets. See the description below for more\n\ + information on this option.\n\ +SSL_ENABLE_SSL3: (default=True)\n\ + Enables the application to communicate with SSL v3. If you turn this\n\ + option off, an attempt to establish a connection with a peer that\n\ + understands only SSL v3 will fail.\n\ +SSL_ENABLE_SSL2: (default=True)\n\ + Enables the application to communicate with SSL v2. If you turn this\n\ + option off, an attempt to establish a connection with a peer that\n\ + understands only SSL v2 will fail.\n\ +SSL_ENABLE_TLS: (default=True)\n\ + Is a peer of the SSL_ENABLE_SSL2 and SSL_ENABLE_SSL3 options. The IETF\n\ + standard Transport Layer Security (TLS) protocol, RFC 2246, is a\n\ + modified version of SSL3. It uses the SSL version number 3.1,\n\ + appearing to be a 'minor' revision of SSL3.0. NSS 2.8 supports TLS in\n\ + addition to SSL2 and SSL3. You can think of it as 'SSL_ENABLE_SSL3.1.'\n\ + See the description below for more information about this option.\n\ +SSL_V2_COMPATIBLE_HELLO: (default=True)\n\ + Tells the SSL library whether or not to send SSL3 client hello\n\ + messages in SSL2-compatible format. If set to True, it will;\n\ + otherwise, it will not. See the description below for more information\n\ + on this option.\n\ +SSL_NO_CACHE: (default=False)\n\ + Disallows use of the session cache. Factory setting is off. If you\n\ + turn this option on, this socket will be unable to resume a session\n\ + begun by another socket. When this socket's session is finished, no\n\ + other socket will be able to resume the session begun by this socket.\n\ +SSL_ROLLBACK_DETECTION: (default=True)\n\ + Disables detection of a rollback attack. Factory setting is on. You\n\ + must turn this option off to interoperate with TLS clients ( such as\n\ + certain versions of Microsoft Internet Explorer) that do not conform\n\ + to the TLS specification regarding rollback attacks. Important:\n\ + turning this option off means that your code will not comply with the\n\ + TLS 3.1 and SSL 3.0 specifications regarding rollback attack and will\n\ + therefore be vulnerable to this form of attack.\n\ + \n\ +Keep the following in mind when deciding on the operating parameters\n\ +you want to use with a particular socket.\n\ +\n\ +Turning on SSL_REQUIRE_CERTIFICATE will have no effect unless\n\ +SSL_REQUEST_CERTIFICATE is also turned on. If you enable\n\ +SSL_REQUEST_CERTIFICATE, then you should explicitly enable or disable\n\ +SSL_REQUIRE_CERTIFICATE rather than allowing it to default. Enabling\n\ +the SSL_REQUIRE_CERTIFICATE option is not recommended. If the client\n\ +has no certificate and this option is enabled, the client's connection\n\ +terminates with an error. The user is likely to think something is\n\ +wrong with either the client or the server, and is unlikely to realize\n\ +that the problem is the lack of a certificate. It is better to allow\n\ +the SSL handshake to complete and then return an error message to the\n\ +client that informs the user of the need for a certificate.\n\ +\n\ +The SSL protocol is defined to be able to handle simultaneous two-way\n\ +communication between applications at each end of an SSL\n\ +connection. Two-way simultaneous communication is also known as'Full\n\ +Duplex', abbreviated FDX. However, most application protocols that use\n\ +SSL are not two-way simultaneous, but two-way alternate, also known as\n\ +'Half Dupled'; that is, each end takes turns sending, and each end is\n\ +either sending, or receiving, but not both at the same time. For an\n\ +application to do full duplex, it would have two threads sharing the\n\ +socket; one doing all the reading and the other doing all the writing.\n\ +\n\ +The SSL_ENABLE_FDX option tells the SSL library whether the\n\ +application will have two threads, one reading and one writing, or\n\ +just one thread doing reads and writes alternately.\n\ +\n\ +If an SSL3 client hello message is sent to a server that only\n\ +understands SSL2 and not SSL3, then the server will interpret the SSL3\n\ +client hello as a very large message, and the connection will usually\n\ +seem to 'hang' while the SSL2 server expects more data that will never\n\ +arrive. For this reason, the SSL3 spec allows SSL3 client hellos to be\n\ +sent in SSL2 format, and it recommends that SSL3 servers all accept\n\ +SSL3 client hellos in SSL2 format. When an SSL2-only server receives\n\ +an SSL3 client hello in SSL2 format, it can (and probably will)\n\ +negotiate the protocol version correctly, not causing a 'hang'.\n\ +\n\ +Some applications may wish to force SSL3 client hellos to be sent in\n\ +SSL3 format, not in SSL2-compatible format. They might wish to do this\n\ +if they knew, somehow, that the server does not understand\n\ +SSL2-compatible client hello messages.\n\ +\n\ +SSL_V2_COMPATIBLE_HELLO tells the SSL library whether or not to send\n\ +SSL3 client hello messages in SSL2-compatible format. Note that\n\ +calling SSLSocket.set_ssl_option() to set SSL_V2_COMPATIBLE_HELLO to\n\ +False implicitly also sets the SSL_ENABLE_SSL2 option to False for\n\ +that SSL socket. Calling SSL_EnableDefault to change the application\n\ +default setting for SSL_V2_COMPATIBLE_HELLO to False implicitly also\n\ +sets the default value for SSL_ENABLE_SSL2 option to False for that\n\ +application.\n\ +\n\ +The options SSL_ENABLE_SSL2, SSL_ENABLE_SSL3, and SSL_ENABLE_TLS can\n\ +each be set to True or False independently of each other. NSS 2.8 and\n\ +later versions will negotiate the highest protocol version with the\n\ +peer application from among the set of protocols that are commonly\n\ +enabled in both applications.\n\ +\n\ +Note that SSL3 and TLS share the same set of cipher suites. When both\n\ +SSL3 and TLS are enabled, all SSL3/TLS cipher suites that are enabled\n\ +are enabled for both SSL3 and TLS.\n\ +\n\ +When an application imports a socket into SSL after the TCP connection\n\ +on that socket has already been established, it must call\n\ +SSLSocket.reset_handshake() to indicate whether the socket is for a\n\ +client or server. At first glance this may seem unnecessary, since\n\ +SSLSocket.set_ssl_option() can set SSL_HANDSHAKE_AS_CLIENT or\n\ +SSL_HANDSHAKE_AS_SERVER. However, these settings control the behavior\n\ +of SSLSocket.connect() and SSLSocket.accept() only; if you don't call\n\ +one of those functions after importing a non-SSL socket with\n\ +SSL_Import (as in the case of an already established TCP connection),\n\ +SSL still needs to know whether the application is functioning as a\n\ +client or server.\n\ +\n\ +If a socket file descriptor is imported as an SSL socket before it is\n\ +connected, it is implicitly configured to handshake as a client or\n\ +handshake as a server when the connection is made. If the application\n\ +calls SSLSocket.connect() (connecting as a TCP client), then the SSL\n\ +socket is (by default) configured to handshake as an SSL client. If\n\ +the application calls SSLSocket.accept() (connecting the socket as a\n\ +TCP server) then the SSL socket is (by default) configured to\n\ +handshake as an SSL server. SSL_HANDSHAKE_AS_CLIENT and\n\ +SSL_HANDSHAKE_AS_SERVER control this implicit configuration. Both\n\ +SSL_HANDSHAKE_AS_CLIENT and SSL_HANDSHAKE_AS_SERVER are initially set\n\ +to off--that is, the process default for both values is False when the\n\ +process begins. The process default can be changed from the initial\n\ +values by using SSL_EnableDefault, and the value for a particular\n\ +socket can be changed by using SSLSocket.set_ssl_option().\n\ +\n\ +If a socket that is already connected gets imported into SSL after it\n\ +has been connected (that is, after SSLSocket.accept() or\n\ +SSLSocket.connect() has returned), then no implicit SSL handshake\n\ +configuration as a client or server will have been done by\n\ +SSLSocket.connect() or SSLSocket.accept() on that socket. In this\n\ +case, a call to SSLSocket.reset_handshake() is required to explicitly\n\ +configure the socket to handshake as a client or as a server. If\n\ +SSLSocket.reset_handshake() is not called to explicitly configure the\n\ +socket handshake, a crash is likely to occur when the first I/O\n\ +operation is done on the socket after it is imported into SSL.\n\ +"); + +static PyObject * +SSLSocket_set_ssl_option(SSLSocket *self, PyObject *args) +{ + int option; + int value; + + TraceMethodEnter("SSLSocket_set_ssl_option", self); + + /* + * Note, although most of the options are booleans, at least one + * isn't, SSL_REQUIRE_CERTIFICATE, so we can't use Python Booleans + * and must use integers instead. + */ + + if (!PyArg_ParseTuple(args, "ii:set_ssl_option", &option, &value)) { + return NULL; + } + + if (SSL_OptionSet(self->pr_socket, option, value) != SECSuccess) { + return set_nspr_error(NULL); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_get_ssl_option_doc, +"get_ssl_option(value) -> value\n\ +\n\ +:Parameters:\n\ + value : integer\n\ + a constant value identifying which option to query\n\ +\n\ +Retrieves the value of a specified SSL option. Refer to the\n\ +documentation for SSLSocket.set_ssl_option() for an explanation of the\n\ +possible values.\n\ +"); + +static PyObject * +SSLSocket_get_ssl_option(SSLSocket *self, PyObject *args) +{ + int option; + int value; + + TraceMethodEnter("SSLSocket_get_ssl_option", self); + + if (!PyArg_ParseTuple(args, "i:get_ssl_option", &option)) { + return NULL; + } + + if (SSL_OptionGet(self->pr_socket, option, &value) != SECSuccess) { + return set_nspr_error(NULL); + } + + return PyInt_FromLong(value); +} + +PyDoc_STRVAR(SSLSocket_accept_doc, +"accept(timeout=PR_INTERVAL_NO_TIMEOUT) -> (Socket, NetworkAddress)\n\ +\n\ +:Parameters:\n\ + timeout : integer\n\ + optional timeout value expressed as a NSPR interval\n\ +\n\ +The socket is a rendezvous socket that has been bound to an address\n\ +with Socket.bind() and is listening for connections after a call to\n\ +Socket.listen(). Socket.accept() accepts the first connection from the\n\ +queue of pending connections and creates a new socket for the newly\n\ +accepted connection. The rendezvous socket can still be used to accept\n\ +more connections.\n\ +\n\ +Socket.accept() blocks the calling thread until either a new\n\ +connection is successfully accepted or an error occurs. If the timeout\n\ +parameter is not PR_INTERVAL_NO_TIMEOUT and no pending connection can\n\ +be accepted before the time limit, Socket.accept() raises a\n\ +nss.error.NSPRError exception with the error code PR_IO_TIMEOUT_ERROR.\n\ +\n\ +Socket.accept() returns a tuple containing a new Socket object and\n\ +Networkaddress object for the peer.\n\ +"); + +static PyObject * +SSLSocket_accept(SSLSocket *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"timeout", NULL}; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + PRNetAddr pr_netaddr; + PyObject *py_ssl_socket = NULL; + PyObject *py_netaddr = NULL; + PRFileDesc *pr_socket = NULL; + PyObject *return_value = NULL; + + TraceMethodEnter("SSLSocket_accept", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|I:accept", kwlist, + &timeout)) + return NULL; + + if ((pr_socket = PR_Accept(self->pr_socket, &pr_netaddr, timeout)) == NULL) + return set_nspr_error(NULL); + + if ((py_netaddr = NetworkAddress_new_from_prnetaddr(&pr_netaddr)) == NULL) + goto error; + + if ((py_ssl_socket = SSLSocket_new_from_prfiledesc(pr_socket, self->family)) == NULL) + goto error; + + if ((return_value = Py_BuildValue("OO", py_ssl_socket, py_netaddr)) == NULL) + goto error; + + return return_value; + + error: + Py_XDECREF(py_ssl_socket); + Py_XDECREF(py_netaddr); + Py_XDECREF(return_value); + return NULL; +} + +static SECStatus +ssl_auth_certificate(void *arg, PRFileDesc *pr_socket, PRBool check_sig, PRBool is_server) +{ + SSLSocket *self = arg; + PyObject *py_ssl_socket = NULL; + PyObject *result = NULL; + PyObject *args = NULL; + PyObject *item; + Py_ssize_t argc; + int i, j; + SECStatus sec_status; + + argc = 3; + if (self->auth_certificate_callback_data) + argc += PyTuple_Size(self->auth_certificate_callback_data); + + if ((args = PyTuple_New(argc)) == NULL) { + PySys_WriteStderr("SSLSocket.auth_certificate_func: out of memory\n"); + return SECFailure; + } + + if ((py_ssl_socket = SSLSocket_new_from_prfiledesc(pr_socket, self->family)) == NULL) { /* FIXME: cached? what is family? */ + PySys_WriteStderr("SSLSocket.auth_certificate_func: cannot create socket object\n"); + return SECFailure; + } + + PyTuple_SetItem(args, 0, py_ssl_socket); + PyTuple_SetItem(args, 1, PyBool_FromLong(check_sig)); + PyTuple_SetItem(args, 2, PyBool_FromLong(is_server)); + + for (i = 3, j = 0; i < argc; i++, j++) { + item = PyTuple_GetItem(self->auth_certificate_callback_data, j); + Py_INCREF(item); + PyTuple_SetItem(args, i, item); + } + + if ((result = PyObject_CallObject(self->auth_certificate_callback, args)) == NULL) { + PySys_WriteStderr("exception in SSLSocket.auth_certificate_func\n"); + PyErr_Print(); /* this also clears the error */ + Py_DECREF(args); + return SECFailure; + } + + sec_status = PyObject_IsTrue(result) ? SECSuccess : SECFailure; + + Py_DECREF(args); + Py_XDECREF(result); + + return sec_status; +} + +PyDoc_STRVAR(SSLSocket_set_auth_certificate_callback_doc, +"set_auth_certificate_callback(callback, [user_data1, ...])\n\ +\n\ +:Parameters:\n\ + callback : function pointer\n\ + callback to invoke\n\ + user_dataN:\n\ + zero or more caller supplied parameters which will be passed to the callback\n\ +\n\ +The callback has the following signature::\n\ + \n\ + callback(socket, check_sig, is_server, [user_data1, ...]) -> bool\n\ +\n\ +socket\n\ + the SSLSocket object\n\ +check_sig\n\ + boolean, True means signatures are to be checked and the\n\ + certificate chain is to be validated. False means they are not\n\ + to be checked. (The value is normally True.)\n\ +is_server\n\ + boolean, True means the callback function should evaluate the\n\ + certificate as a server does, treating the remote end as a\n\ + client. False means the callback function should evaluate the\n\ + certificate as a client does, treating the remote end as a server.\n\ +user_dataN\n\ + zero or more caller supplied optional parameters\n\ +\n\ +The callback function should return True if authentication is\n\ +successful, False otherwise. If authentication is not successful the\n\ +callback should indicate the reason for the failure (if possible) by\n\ +calling nss.set_error() with the appropriate error code.\n\ +\n\ +The callback function obtains the certificate to be authenticated by\n\ +calling ssl.get_peer_certificate(). If is_server is false, the\n\ +callback should also check that the domain name in the remote server's\n\ +certificate matches the desired domain name specified in a previous\n\ +call to ssl.set_hostname(). To obtain that domain name, the callback calls\n\ +ssl.get_hostname(). \n\ +\n\ +The callback may need to call one or more PK11 functions to obtain the\n\ +services of a PKCS 11 module. Some of the PK11 functions require a\n\ +PIN argument (see ssl.set_pkcs11_pin_arg() for details). To obtain the\n\ +value that was set with ssl.set_pkcs11_pin_arg(), the callback calls\n\ +ssl.get_pkcs11_pin_arg().\n\ +\n\ +If the callback returns False, the SSL connection is terminated\n\ +immediately unless the application has supplied a bad-certificate\n\ +callback function by having previously called\n\ +ssl.set_bad_cert_callback(). A bad-certificate callback function gives\n\ +the application the opportunity to choose to accept the certificate as\n\ +authentic and authorized even though it failed the check performed by\n\ +the certificate authentication callback function.\n\ +\n\ +Example::\n\ + \n\ + def auth_certificate_callback(sock, check_sig, is_server, certdb):\n\ + validity = False\n\ + \n\ + cert = sock.get_peer_certificate()\n\ + pin_args = sock.get_pkcs11_pin_arg()\n\ + \n\ + # Define how the cert is being used based upon the is_server flag.\n\ + # This may seem backwards, but isn't.\n\ + if is_server:\n\ + cert_usage = nss.certificateUsageSSLClient\n\ + else:\n\ + cert_usage = nss.certificateUsageSSLServer\n\ + \n\ + valid_usage = cert.verify_now(certdb, check_sig, cert_usage, *pin_args)\n\ + \n\ + if valid_usage & cert_usage:\n\ + validity = True\n\ + else:\n\ + validity = False\n\ + \n\ + # If this is a server, we're finished\n\ + if is_server or not validity:\n\ + return validity\n\ + \n\ + # Certificate is OK. Since this is the client side of an SSL\n\ + # connection, we need to verify that the name field in the cert\n\ + # matches the desired hostname. This is our defense against\n\ + # man-in-the-middle attacks.\n\ + \n\ + hostname = sock.get_hostname()\n\ + validity = cert.verify_hostname(hostname)\n\ + \n\ + return validity\n\ + \n\ + sock = ssl.SSLSocket()\n\ + sock.set_auth_certificate_callback(auth_certificate_callback, nss.get_default_certdb())\n\ +\n\ +"); + +static PyObject * +SSLSocket_set_auth_certificate_callback(SSLSocket *self, PyObject *args) +{ + Py_ssize_t argc; + PyObject *callback; + PyObject *callback_args = NULL; + + TraceMethodEnter("SSLSocket_set_auth_certificate_callback", self); + + argc = PyTuple_Size(args); + + if ((callback = PyTuple_GetItem(args, 0)) == NULL) { + PyErr_SetString(PyExc_TypeError, "set_auth_certificate_callback: missing callback argument"); + return NULL; + } + + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "callback must be callable"); + return NULL; + } + + callback_args = PyTuple_GetSlice(args, 1, argc); + + Py_INCREF(callback); + Py_XDECREF(self->auth_certificate_callback); + self->auth_certificate_callback = callback; + + Py_INCREF(callback_args); + Py_XDECREF(self->auth_certificate_callback_data); + self->auth_certificate_callback_data = callback_args; + + if (SSL_AuthCertificateHook(self->pr_socket, ssl_auth_certificate, self) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + + +static SECStatus +get_client_auth_data(void *arg, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey) +{ + SSLSocket *self = arg; + PyObject *return_args = NULL; + PyObject *args = NULL; + PyObject *item; + Py_ssize_t argc, return_argc; + int i, j; + PyObject *py_cert_dist_names = NULL; + PyObject *py_cert = NULL; + PyObject *py_priv_key = NULL; + + argc = 1; + if (self->client_auth_data_callback_data) + argc += PyTuple_Size(self->client_auth_data_callback_data); + + if ((args = PyTuple_New(argc)) == NULL) { + PySys_WriteStderr("SSLSocket.client_auth_data_callback: out of memory\n"); + return SECFailure; + } + + if ((py_cert_dist_names = cert_distnames_new_from_CERTDistNames(caNames)) == NULL) { + PySys_WriteStderr("SSLSocket.client_auth_data_callback: out of memory\n"); + goto fail; + } + + PyTuple_SetItem(args, 0, (PyObject *)py_cert_dist_names); + + for (i = 1, j = 0; i < argc; i++, j++) { + item = PyTuple_GetItem(self->client_auth_data_callback_data, j); + Py_INCREF(item); + PyTuple_SetItem(args, i, item); + } + + if ((return_args = PyObject_CallObject(self->client_auth_data_callback, args)) == NULL) { + PySys_WriteStderr("exception in SSLSocket.client_auth_data_callback\n"); + PyErr_Print(); + goto fail; + } + + return_argc = PyTuple_Size(return_args); + + py_cert = PyTuple_GetItem(return_args, 0); + if (py_cert == Py_None) { + // callback returned failure + goto fail; + } + + if (!PyCertificate_Check(py_cert)) { + PySys_WriteStderr("SSLSocket.client_auth_data_callback: 1st return value must be %s or None\n", CertificateType.tp_name); + PyErr_Print(); + goto fail; + } + + if (return_argc < 2) { + PySys_WriteStderr("SSLSocket.client_auth_data_callback: expected 2nd return value\n"); + PyErr_Print(); + goto fail; + } + + py_priv_key = PyTuple_GetItem(return_args, 1); + if (py_priv_key == Py_None) { + // callback returned failure + goto fail; + } + + if (!PyPrivateKey_Check(py_priv_key)) { + PySys_WriteStderr("SSLSocket.client_auth_data_callback: 2nd return value must be %s or None\n", PrivateKeyType.tp_name); + PyErr_Print(); + goto fail; + } + + Py_DECREF(args); + Py_DECREF(py_cert_dist_names); + // FIXME: what should we do with the ref count for the certificate & private key? + // we can't let them be destroyed while the NSS API is using them + // but when will we get a chance after this callback returns to destroy them? + Py_INCREF(py_cert); + Py_INCREF(py_priv_key); + Py_DECREF(return_args); + + *pRetCert = ((Certificate *)py_cert)->cert; + *pRetKey = ((PrivateKey *)py_priv_key)->private_key; + return SECSuccess; + + fail: + Py_XDECREF(args); + Py_XDECREF(py_cert_dist_names); + Py_XDECREF(py_cert); + Py_XDECREF(py_priv_key); + Py_XDECREF(return_args); + return SECFailure; +} + +PyDoc_STRVAR(SSLSocket_set_client_auth_data_callback_doc, +"set_client_auth_data_callback(callback, [user_data1, ...])\n\ +\n\ +:Parameters:\n\ + callback : function pointer\n\ + callback to invoke\n\ + user_dataN:\n\ + zero or more caller supplied parameters which will be passed to the callback\n\ +\n\ +The callback has the following signature::\n\ + \n\ + callback(ca_names, [user_data1, ...]) -> (Certificate, PrivateKey)\n\ +\n\ +ca_names\n\ + Sequence of CA distinguished names that the server accepts. Each\n\ + item in the sequence must be a SecItem object containing a\n\ + distinguished name.\n\ +user_dataN\n\ + zero or more caller supplied optional parameters\n\ +\n\ +The callback returns Certificate and PrivateKey if successful,\n\ +or None if the callback failed.\n\ +\n\ +Defines a callback function for SSL to use in a client application\n\ +when a server asks for client authentication information. This\n\ +callback function is required if your client application is going to\n\ +support client authentication.\n\ +\n\ +The callback function set with SSLSocket.set_client_auth_data_callback()\n\ +is used to get information from a client application when\n\ +authentication is requested by the server. The callback function\n\ +retrieves the client's private key and certificate. SSL provides an\n\ +implementation of this callback function; see NSS_GetClientAuthData\n\ +for details. Unlike SSL_AuthCertificate, NSS_GetClientAuthData is not\n\ +a default callback function. You must set it explicitly with\n\ +SSLSocket.set_client_auth_data_callback() if you want to use it.\n\ +\n\ +Example::\n\ + \n\ + def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):\n\ + cert = None\n\ + if chosen_nickname:\n\ + try:\n\ + cert = nss.find_cert_from_nickname(chosen_nickname, password)\n\ + priv_key = nss.find_key_by_any_cert(cert, password)\n\ + return cert, priv_key\n\ + except NSPRError, e:\n\ + return False\n\ + else:\n\ + nicknames = nss.get_cert_nicknames(certdb, nss.SEC_CERT_NICKNAMES_USER)\n\ + for nickname in nicknames:\n\ + try:\n\ + cert = nss.find_cert_from_nickname(nickname, password)\n\ + if cert.check_valid_times():\n\ + if cert.has_signer_in_ca_names(ca_names):\n\ + priv_key = nss.find_key_by_any_cert(cert, password)\n\ + return cert, priv_key\n\ + except NSPRError, e:\n\ + pass\n\ + return False\n\ + \n\ + sock = ssl.SSLSocket()\n\ + sock.set_client_auth_data_callback(client_auth_data_callback, nickname, password, nss.get_default_certdb())\n\ +\n\ +"); + +static PyObject * +SSLSocket_set_client_auth_data_callback(SSLSocket *self, PyObject *args) +{ + Py_ssize_t argc; + PyObject *callback; + PyObject *callback_args = NULL; + + TraceMethodEnter("SSLSocket_set_client_auth_data_callback", self); + + argc = PyTuple_Size(args); + + if ((callback = PyTuple_GetItem(args, 0)) == NULL) { + PyErr_SetString(PyExc_TypeError, "set_client_auth_data_callback: missing callback argument"); + return NULL; + } + + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "callback must be callable"); + return NULL; + } + + callback_args = PyTuple_GetSlice(args, 1, argc); + + Py_INCREF(callback); + Py_XDECREF(self->client_auth_data_callback); + self->client_auth_data_callback = callback; + + Py_INCREF(callback_args); + Py_XDECREF(self->client_auth_data_callback_data); + self->client_auth_data_callback_data = callback_args; + + if (SSL_GetClientAuthDataHook(self->pr_socket, get_client_auth_data, self) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +static void +ssl_handshake_callback(PRFileDesc *fd, void *arg) +{ + SSLSocket *self = arg; + PyObject *result = NULL; + PyObject *args = NULL; + PyObject *item; + Py_ssize_t argc; + int i, j; + + argc = 1; + if (self->handshake_callback_data) + argc += PyTuple_Size(self->handshake_callback_data); + + if ((args = PyTuple_New(argc)) == NULL) { + PySys_WriteStderr("SSLSocket.handshake_callback: out of memory\n"); + return; + } + + Py_INCREF(self); + PyTuple_SetItem(args, 0, (PyObject *)self); + + for (i = 1, j = 0; i < argc; i++, j++) { + item = PyTuple_GetItem(self->handshake_callback_data, j); + Py_INCREF(item); + PyTuple_SetItem(args, i, item); + } + + if ((result = PyObject_CallObject(self->handshake_callback, args)) == NULL) { + PySys_WriteStderr("exception in SSLSocket.handshake_callback\n"); + PyErr_Print(); /* this also clears the error */ + Py_DECREF(args); + return; + } + + Py_DECREF(args); +} + +PyDoc_STRVAR(SSLSocket_set_handshake_callback_doc, +"set_handshake_callback(callback, [user_data1, ...])\n\ +\n\ +:Parameters:\n\ + callback : function pointer\n\ + callback to invoke\n\ + user_dataN:\n\ + zero or more caller supplied parameters which will be passed to the callback\n\ +\n\ +The callback has the following signature::\n\ + \n\ + callback(socket, [user_data1, ...])\n\ +\n\ +socket\n\ + the SSL socket the handshake has completed on\n\ +user_dataN\n\ + zero or more caller supplied optional parameters\n\ +\n\ +Sets up a callback function used by SSL to inform either a client\n\ +application or a server application when the handshake is completed.\n\ +\n\ +Example::\n\ + \n\ + def handshake_callback(sock):\n\ + print 'handshake complete, peer = %s' % (sock.get_peer_name())\n\ + \n\ + sock = ssl.SSLSocket()\n\ + sock.set_handshake_callback(handshake_callback)\n\ +\n\ +"); + +static PyObject * +SSLSocket_set_handshake_callback(SSLSocket *self, PyObject *args) +{ + Py_ssize_t argc; + PyObject *callback; + PyObject *callback_args = NULL; + + TraceMethodEnter("SSLSocket_set_handshake_callback", self); + + argc = PyTuple_Size(args); + + if ((callback = PyTuple_GetItem(args, 0)) == NULL) { + PyErr_SetString(PyExc_TypeError, "set_handshake_callback: missing callback argument"); + return NULL; + } + + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "callback must be callable"); + return NULL; + } + + callback_args = PyTuple_GetSlice(args, 1, argc); + + Py_INCREF(callback); + Py_XDECREF(self->handshake_callback); + self->handshake_callback = callback; + + Py_INCREF(callback_args); + Py_XDECREF(self->handshake_callback_data); + self->handshake_callback_data = callback_args; + + if (SSL_HandshakeCallback(self->pr_socket, ssl_handshake_callback, self) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + + +PyDoc_STRVAR(SSLSocket_set_pkcs11_pin_arg_doc, +"set_pkcs11_pin_arg([user_dataN, ...])\n\ +\n\ +:Parameters:\n\ + user_dataN : object ...\n\ + zero or more caller supplied parameters which will be passed\n\ + to the pk11.password_callback()\n\ +"); + +static PyObject * +SSLSocket_set_pkcs11_pin_arg(SSLSocket *self, PyObject *args) +{ + TraceMethodEnter("SSLSocket_set_pkcs11_pin_arg", self); + + Py_XDECREF(self->pk11_pin_args); + Py_INCREF(args); + self->pk11_pin_args = args; + if (SSL_SetPKCS11PinArg(self->pr_socket, args) != SECSuccess) { + Py_DECREF(self->pk11_pin_args); + self->pk11_pin_args = NULL; + return set_nspr_error(NULL); + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_get_pkcs11_pin_arg_doc, +"get_pkcs11_pin_arg()\n\ +\n\ +Returns a tuple of arguments or None if not previously set with\n\ +SSLSocket.set_pkcs11_pin_arg()\n\ +"); + +static PyObject * +SSLSocket_get_pkcs11_pin_arg(SSLSocket *self, PyObject *args) +{ + PyObject *pk11_pin_args = NULL; + + TraceMethodEnter("SSLSocket_get_pkcs11_pin_arg", self); + + self->pk11_pin_args = args; + pk11_pin_args = SSL_RevealPinArg(self->pr_socket); + + assert(pk11_pin_args == self->pk11_pin_args); + + if (pk11_pin_args == NULL) + Py_RETURN_NONE; + + Py_INCREF(pk11_pin_args); + return pk11_pin_args; +} + +PyDoc_STRVAR(SSLSocket_config_secure_server_doc, +"config_secure_server(cert, key, kea)\n\ +\n\ +:Parameters:\n\ + cert : Certificate object\n\ + Server's certificate as a Certificate object\n\ + key : PrivateKey object\n\ + Server's private key as a PrivateKey object\n\ + kea : integer\n\ + Key exchange type (e.g. ssl_kea_rsa, ssl_kea_dh, etc.)\n\ +\n\ +Configures a listen socket with the information needed to handshake as\n\ +an SSL server. SSLSocket.config_secure_server() requires the\n\ +certificate for the server and the server's private key.\n\ +"); + +static PyObject * +SSLSocket_config_secure_server(SSLSocket *self, PyObject *args) +{ + Certificate *py_cert = NULL; + PrivateKey *py_priv_key = NULL; + int kea = 0; + + TraceMethodEnter("SSLSocket_config_secure_server", self); + + if (!PyArg_ParseTuple(args, "O!O!i:config_secure_server", + &CertificateType, &py_cert, + &PrivateKeyType, &py_priv_key, + &kea)) + return NULL; + + if (SSL_ConfigSecureServer(self->pr_socket, py_cert->cert, py_priv_key->private_key, kea) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; + +} + +PyDoc_STRVAR(SSLSocket_get_peer_certificate_doc, +"get_peer_certificate() -> Certficate\n\ +\n\ +SSLSocket.get__peer_certificate() is used by certificate\n\ +authentication and bad-certificate callback functions to obtain the\n\ +certificate under scrutiny. If the client calls\n\ +SSLSocket.get_peer_certificate(), it always returns the server's\n\ +certificate. If the server calls SSLSocket.get_peer_certificate(), it\n\ +may return None if client authentication is not enabled or if the\n\ +client had no certificate when asked.\n\ +"); + +static PyObject * +SSLSocket_get_peer_certificate(SSLSocket *self, PyObject *args) +{ + CERTCertificate *cert = NULL; + PyObject *py_cert = NULL; + + cert = SSL_PeerCertificate(self->pr_socket); + if (cert == NULL) + Py_RETURN_NONE; + + if ((py_cert = Certificate_new_from_cert(cert)) == NULL) { + return NULL; + } + + return py_cert; +} + +PyDoc_STRVAR(SSLSocket_get_certificate_doc, +"get_certificate() -> Certficate\n\ +\n\ +Returns the certificate associated with the socket or\n\ +None if not previously set.\n\ +"); + +static PyObject * +SSLSocket_get_certificate(SSLSocket *self, PyObject *args) +{ + CERTCertificate *cert = NULL; + PyObject *py_cert = NULL; + + cert = SSL_RevealCert(self->pr_socket); + if (cert == NULL) + Py_RETURN_NONE; + + if ((py_cert = Certificate_new_from_cert(cert)) == NULL) { + return NULL; + } + + return py_cert; +} + +PyDoc_STRVAR(SSLSocket_invalidate_session_doc, +"invalidate_session()\n\ +\n\ +After you call SSLSSocket.invalidate_session(), the existing\n\ +connection using the session can continue, but no new connections can\n\ +resume this SSL session.\n\ +" +); + +static PyObject * +SSLSocket_invalidate_session(SSLSocket *self, PyObject *args) +{ + TraceMethodEnter("SSLSocket_invalidate_session", self); + + if (SSL_InvalidateSession(self->pr_socket) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_data_pending_doc, +"data_pending()\n\ +\n\ +Returns the number of bytes waiting in internal SSL buffers to be read\n\ +by the local application from the SSL socket.\n\ +\n\ +If SSL_SECURITY has not been enabled with a call to\n\ +SSLSocket.set_ssl_default_option() or SSLSocket.set_ssl_option(), the\n\ +function returns zero.\n\ +" +); + +static PyObject * +SSLSocket_data_pending(SSLSocket *self, PyObject *args) +{ + int data_pending = 0; + + TraceMethodEnter("SSLSocket_data_pending", self); + + data_pending = SSL_DataPending(self->pr_socket); + return PyInt_FromLong(data_pending); +} + +PyDoc_STRVAR(SSLSocket_get_security_status_doc, +"get_security_status() -> on, cipher, key_size, secret_key_size, issuer, subject\n\ +\n\ +Gets information about the security parameters of the current connection.\n\ +Returns the tuple (on, cipher, key_size, secret_key_size, issuer, subject)\n\ +\n\ +The interpretation of each value is:\n\ + on\n\ + An integer, will be one of these values:\n\ + - SSL_SECURITY_STATUS_OFF\n\ + - SSL_SECURITY_STATUS_ON_HIGH\n\ + - SSL_SECURITY_STATUS_ON_LOW\n\ + cipher\n\ + A string specifying the name of the cipher.\n\ + - For SSL v2, the string is one of the following:\n\ + - RC4\n\ + - RC4-Export\n\ + - RC2-CBC\n\ + - RC2-CBC-Export\n\ + - DES-CBC,\n\ + - DES-EDE3-CBC\n\ + - For SSL v3, the string is one of the following:\n\ + - RC4\n\ + - RC4-40\n\ + - RC2-CBC\n\ + - RC2-CBC-40\n\ + - DES-CBC\n\ + - 3DES-EDE-CBC\n\ + - DES-CBC-40\n\ + keySize\n\ + An integer, the session key size used, in bits.\n\ + secret_key_size\n\ + An integer. indicates the size, in bits, of the secret portion of\n\ + the session key used (also known as the 'effective key size'). The\n\ + secret key size is never greater than the session key size.\n\ + issuer\n\ + A string specifying the DN of the issuer of the certificate at\n\ + the other end of the connection, in RFC1485 format. If no\n\ + certificate is supplied, the string is 'no certificate'\n\ + subject\n\ + A string specifying the distinguished name of the certificate at\n\ + the other end of the connection, in RFC1485 format. If no\n\ + certificate is supplied, the string is 'no certificate'\n\ +\n\ +"); + +static PyObject * +SSLSocket_get_security_status(SSLSocket *self, PyObject *args) +{ + int on; + char *cipher = NULL; + int key_size; + int secret_key_size; + char *issuer = NULL; + char *subject = NULL; + PyObject *return_value = NULL; + + TraceMethodEnter("SSLSocket_get_security_status", self); + + if (SSL_SecurityStatus(self->pr_socket, &on, &cipher, &key_size, + &secret_key_size, &issuer, &subject) != SECSuccess) { + set_nspr_error(NULL); + goto exit; + } + + return_value = Py_BuildValue("isiiss", on, cipher, key_size, + secret_key_size, issuer, subject); + + exit: + if (cipher) PR_Free(cipher); + if (issuer) PR_Free(issuer); + if (subject) PR_Free(subject); + + return return_value; +} + +PyDoc_STRVAR(SSLSocket_get_session_id_doc, +"get_session_id() -> id\n\ +\n\ +Returns the SSL session ID as a SecItem.\n\ +" +); + +static PyObject * +SSLSocket_get_session_id(SSLSocket *self, PyObject *args) +{ + SECItem *sec_item = NULL; + PyObject *return_value = NULL; + + TraceMethodEnter("SSLSocket_get_session_id", self); + + if ((sec_item = SSL_GetSessionID(self->pr_socket)) == NULL) + return set_nspr_error(NULL); + + return_value = SecItem_new_from_sec_item(sec_item, SECITEM_session_id); + + SECITEM_FreeItem(sec_item, PR_TRUE); + + return return_value; +} + +PyDoc_STRVAR(SSLSocket_set_sock_peer_id_doc, +"set_sock_peer_id(id)\n\ +\n\ +:Parameters:\n\ + id : integer\n\ + An ID number assigned by the application to keep track of the SSL\n\ + session associated with the peer.\n\ +\n\ +Associates a peer ID with a socket to facilitate looking up the SSL\n\ +session when it is tunneling through a proxy.\n\ +\n\ +SSL peers frequently reconnect after a relatively short time has\n\ +passed. To avoid the overhead of repeating the full SSL handshake in\n\ +situations like this, the SSL protocol supports the use of a session\n\ +cache, which retains information about each connection for some\n\ +predetermined length of time.\n\ +\n\ +For example, a client session cache includes the hostname and port\n\ +number of each server the client connects with, plus additional\n\ +information such as the master secret generated during the SSL\n\ +handshake. For a direct connection with a server, the hostname and\n\ +port number are sufficient for the client to identify the server as\n\ +one for which it has an entry in its session cache. However, the\n\ +situation is more complicated if the client is on an intranet and is\n\ +connecting to a server on the Internet through a proxy. In this case,\n\ +the client first connects to the proxy, and the client and proxy\n\ +exchange messages specified by the proxy protocol that allow the\n\ +proxy, in turn, to connect to the requested server on behalf of the\n\ +client. This arrangement is known as SSL tunneling.\n\ +\n\ +Client session cache entries for SSL connections that tunnel through a\n\ +particular proxy all have the same hostname and port number--that is,\n\ +the hostname and port number of the proxy. To determine whether a\n\ +particular server with which the client is attempting to connect has\n\ +an entry in the session cache, the session cache needs some additional\n\ +information that identifies that server. This additional identifying\n\ +information is known as a peer ID. The peer ID is associated with a\n\ +socket, and must be set before the SSL handshake occurs--that is,\n\ +before the SSL handshake is initiated by a call to a function such as\n\ +SSLSocket.read() or SSLSocket.force_handshake(). To set the peer ID,\n\ +you use SSLSocket.set_sock_peer_id().\n\ +\n\ +In summary, SSL uses three pieces of information to identify a\n\ +server's entry in the client session cache: the hostname, port number,\n\ +and peer ID. In the case of a client that is tunneling through a\n\ +proxy, the hostname and port number identify the proxy, and the peer\n\ +ID identifies the desired server. It is recommended that the client\n\ +set the peer ID to a string that consists of the server's hostname and\n\ +port number, like this:'www.hostname.com:387'. This convention\n\ +guarantees that each server has a unique entry in the client session\n\ +cache.\n\ +"); + +static PyObject * +SSLSocket_set_sock_peer_id(SSLSocket *self, PyObject *args) +{ + char *id = NULL; + + TraceMethodEnter("SSLSocket_set_sock_peer_id", self); + + if (!PyArg_ParseTuple(args, "s:set_sock_peer_id")) + return NULL; + + if (SSL_SetSockPeerID(self->pr_socket, id) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_set_cipher_pref_doc, +"set_cipher_pref(cipher, enabled)\n\ +\n\ +:Parameters:\n\ + cipher : integer\n\ + The cipher suite enumeration (e.g. SSL_RSA_WITH_NULL_MD5, etc.)\n\ + enabled : bool\n\ + Boolean value\n\ +\n\ +Sets preference for the specified SSL2, SSL3, or TLS cipher on the\n\ +socket. A cipher suite is used only if the policy allows it and the\n\ +preference for it is set to True.\n\ +\n\ +This function must be called once for each cipher you want to enable\n\ +or disable by default.\n\ +\n\ +Note, which cipher suites are permitted or disallowed are modified by\n\ +previous calls to one or more of the SSL Export Policy Functions.\n\ +"); + +static PyObject * +SSLSocket_set_cipher_pref(SSLSocket *self, PyObject *args) +{ + int cipher; + int enabled; + + TraceMethodEnter("SSLSocket_set_cipher_pref", self); + + if (!PyArg_ParseTuple(args, "ii:set_cipher_pref", &cipher, &enabled)) + return NULL; + + if (SSL_CipherPrefSet(self->pr_socket, cipher, enabled) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_get_cipher_pref_doc, +"get_cipher_pref(cipher) -> enabled\n\ +\n\ +:Parameters:\n\ + cipher : integer\n\ + The cipher suite enumeration (e.g. SSL_RSA_WITH_NULL_MD5, etc.)\n\ +\n\ +Returns the preference for the specified SSL2, SSL3, or TLS cipher on\n\ +the socket.\n\ +"); + +static PyObject * +SSLSocket_get_cipher_pref(SSLSocket *self, PyObject *args) +{ + int cipher; + int enabled; + + TraceMethodEnter("SSLSocket_get_cipher_pref", self); + + if (!PyArg_ParseTuple(args, "i:get_cipher_pref", &cipher)) + return NULL; + + if (SSL_CipherPrefGet(self->pr_socket, cipher, &enabled) != SECSuccess) + return set_nspr_error(NULL); + + if (enabled) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(SSLSocket_set_hostname_doc, +"set_hostname(url)\n\ +\n\ +:Parameters:\n\ + url : string\n\ + A string specifying the desired server's domain name.\n\ +\n\ +The client application's certificate authentication callback function\n\ +needs to compare the domain name in the server's certificate against\n\ +the domain name of the server the client was attempting to\n\ +contact. This step is vital because it is the client's only protection\n\ +against a man-in-the-middle attack. The client application uses\n\ +SSLSocket.set_hostname() to set the domain name of the desired server\n\ +before performing the first SSL handshake. The client application's\n\ +certificate authentication callback function gets this string by\n\ +calling SSLSocket.get_hostname().\n\ +"); + +static PyObject * +SSLSocket_set_hostname(SSLSocket *self, PyObject *args) +{ + char *url = NULL; + + TraceMethodEnter("SSLSocket_set_hostname", self); + + if (!PyArg_ParseTuple(args, "s:set_hostname", &url)) + return NULL; + + if (SSL_SetURL(self->pr_socket, url) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_get_hostname_doc, +"get_hostname()\n\ +\n\ +SSLSocket.get_hostname() is used by certificate authentication callback\n\ +function to obtain the domain name of the desired SSL server for the\n\ +purpose of comparing it with the domain name in the certificate\n\ +presented by the server actually contacted.\n\ +"); + +static PyObject * +SSLSocket_get_hostname(SSLSocket *self, PyObject *args) +{ + char *url = NULL; + PyObject *py_hostname = NULL; + + TraceMethodEnter("SSLSocket_get_hostname", self); + + if ((url = SSL_RevealURL(self->pr_socket)) == NULL) + return set_nspr_error(NULL); + + py_hostname = PyString_FromString(url); + PR_Free(url); + return py_hostname; +} + +PyDoc_STRVAR(SSLSocket_set_certificate_db_doc, +"set_certificate_db(certdb)\n\ +\n\ +:Parameters:\n\ + certdb : CertDB object\n\ + The certification database as a CertDB object\n\ +\n\ +Sets the Certificate Database on a specific SSLSocket.\n\ +" +); + +static PyObject * +SSLSocket_set_certificate_db(SSLSocket *self, PyObject *args) +{ + CertDB *py_certdb = NULL; + + if (!PyArg_ParseTuple(args, "O!:set_certificate_db", CertDBType, &py_certdb)) + return NULL; + + if (SSL_CertDBHandleSet(self->pr_socket, py_certdb->handle) != SECSuccess) + return set_nspr_error(NULL); + + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_reset_handshake_doc, +"reset_handshake(as_server)\n\ +\n\ +:Parameters:\n\ + as_server : bool\n\ + - True means the socket will attempt\n\ + to handshake as a server the next time it tries, and\n\ + - False means the socket will attempt to handshake as\n\ + a client the next time it tries.\n\ +\n\ +Calling SSLSocket.reset_handshake() causes the SSL handshake protocol\n\ +to start from the beginning on the next I/O operation. That is, the\n\ +handshake starts with no cipher suite already in use, just as it does\n\ +on the first handshake on a new socket. When an application imports a\n\ +socket into SSL after the TCP connection on that socket has already\n\ +been established, it must call SSLSocket.reset_handshake() to\n\ +determine whether SSL should behave like an SSL client or an SSL\n\ +server. Note that this step would not be necessary if the socket\n\ +weren't already connected. For an SSL socket that is configured before\n\ +it is connected, SSL figures this out when the application calls\n\ +SSLSocket.connect() or SSLSocket.accept(). If the socket is already\n\ +connected before SSL gets involved, you must provide this extra hint.\n\ +"); + +static PyObject * +SSLSocket_reset_handshake(SSLSocket *self, PyObject *args) +{ + int as_server = 0; + + TraceMethodEnter("SSLSocket_reset_handshake", self); + + if (!PyArg_ParseTuple(args, "i:reset_handshake", &as_server)) + return NULL; + + if (SSL_ResetHandshake(self->pr_socket, as_server) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; + +} + +PyDoc_STRVAR(SSLSocket_force_handshake_doc, +"force_handshake()\n\ +\n\ +Drives a handshake for a specified SSLSocket to completion on a\n\ +socket that has already been prepared to do a handshake or is in the\n\ +middle of doing a handshake.\n\ +\n\ +When you are forcing the initial handshake on a blocking socket, this\n\ +function returns when the handshake is complete. For subsequent\n\ +handshakes, the function can return either because the handshake is\n\ +complete, or because application data has been received on the\n\ +connection that must be processed (that is, the application must read\n\ +it) before the handshake can continue. You can use\n\ +SSLSocket.force_handshake() when a handshake is desired but neither\n\ +end has anything to say immediately. This occurs, for example, when an\n\ +HTTPS server has received a request and determines that before it can\n\ +answer the request, it needs to request an authentication certificate\n\ +from the client. At the HTTP protocol level, nothing more is being\n\ +said (that is, no HTTP request or response is being sent), so the\n\ +server uses SSLSocket.force_handshake() to make the handshake\n\ +occur. SSLSocket.force_handshake() does not prepare a socket to do a\n\ +handshake by itself. The following functions prepare a socket to do a\n\ +handshake:\n\ +\n\ + * SSLSocket.connect()\n\ + * SSLSocket.accept()\n\ + * SSLSocket.rehandshake()\n\ + (after the first handshake is finished)\n\ + * SSLSocket.reset_handshake\n\ + (for sockets that were connected or accepted prior to being imported)\n\ +\n\ +A call to SSLSocket.force_handshake() will almost always be preceded\n\ +by one of those functions. In versions prior to NSS 1.2, you cannot\n\ +force a subsequent handshake. If you use this function after the\n\ +initial handshake, it returns immediately without forcing a handshake.\n\ +" +); + +static PyObject * +SSLSocket_force_handshake(SSLSocket *self, PyObject *args) +{ + if (SSL_ForceHandshake(self->pr_socket) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_force_handshake_timeout_doc, +"force_handshake_timeout(timeout)\n\ +\n\ +:Parameters:\n\ + timeout : integer\n\ + timeout value expressed as a NSPR interval\n\ +\n\ +See the documentation for SSLSocket.force_handshake(). This function\n\ +adds a timeout interval.\n\ +"); + +static PyObject * +SSLSocket_force_handshake_timeout(SSLSocket *self, PyObject *args) +{ + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + + if (!PyArg_ParseTuple(args, "I:force_handshake_timeout", &timeout)) + return NULL; + + if (SSL_ForceHandshakeWithTimeout(self->pr_socket, timeout) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_rehandshake_doc, +"rehandshake(flush_cache)\n\ +\n\ +:Parameters:\n\ + flush_cache : bool\n\ + - If flush_cache is True, the SSL3 cache entry will be flushed\n\ + first, ensuring that a full SSL handshake from scratch will\n\ + occur.\n\ + - If flush_cache is False, and an SSL connection is established, it\n\ + will do the much faster session restart handshake. This will\n\ + regenerate the symmetric session keys without doing another\n\ + private key operation.\n\ + \n\ +\n\ +Causes SSL to begin a new SSL 3.0 handshake on a connection that has\n\ +already completed one handshake.\n\ +\n\ +If flush_cache is True, the SSLSocket.rehandshake() function\n\ +invalidates the current SSL session associated with the specified\n\ +SSLSocket from the session cache and starts another full SSL 3.0\n\ +handshake. It is for use with SSL 3.0 only. You can call this function\n\ +to redo the handshake if you have changed one of the socket's\n\ +configuration parameters (for example, if you are going to request\n\ +client authentication). Setting flush_cache to False can be useful,\n\ +for example, if you are using export ciphers and want to keep changing\n\ +the symmetric keys to foil potential\n\ +attackers. SSLSocket.rehandshake() only initiates the new handshake by\n\ +sending the first message of that handshake. To drive the new\n\ +handshake to completion, you must either call\n\ +SSLSocket.force_handshake() or do another I/O operation (read or\n\ +write) on the socket. A call to SSLSocket.rehandshake() is typically\n\ +followed by a call to SSLSocket.force_handshake().\n\ +"); + +static PyObject * +SSLSocket_rehandshake(SSLSocket *self, PyObject *args) +{ + int flush_cache; + + if (!PyArg_ParseTuple(args, "i:rehandshake", &flush_cache)) + return NULL; + + if (SSL_ReHandshake(self->pr_socket, flush_cache) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_rehandshake_timeout_doc, +"rehandshake_timeout(flush_cache, timeout)\n\ +\n\ +:Parameters:\n\ + flush_cache : bool\n\ + cache flush flag\n\ + timeout : integer\n\ + timeout value expressed as a NSPR interval\n\ +\n\ +See the documentation for SSLSocket.rehandshake(). This function\n\ +adds a timeout interval.\n\ +"); + +static PyObject * +SSLSocket_rehandshake_timeout(SSLSocket *self, PyObject *args) +{ + int flush_cache; + unsigned int timeout = PR_INTERVAL_NO_TIMEOUT; + + if (!PyArg_ParseTuple(args, "iI:rehandshake_timeout", &flush_cache, &timeout)) + return NULL; + + if (SSL_ReHandshakeWithTimeout(self->pr_socket, flush_cache, timeout) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSLSocket_import_tcp_socket_doc, +"import_tcp_socket(osfd) -> Socket\n\ +:Parameters:\n\ + osfd : integer\n\ + file descriptor of the SOCK_STREAM socket to import\n\ +\n\ +Returns a Socket object that uses the specified socket file descriptor for\n\ +communication.\n\ +"); + +static PyObject * +SSLSocket_import_tcp_socket(Socket *unused_class, PyObject *args) +{ + int osfd; + PRFileDesc *sock0, *sock; + PRNetAddr addr; + PyObject *return_value = NULL; + + if (!PyArg_ParseTuple(args, "i:import_tcp_socket", &osfd)) + return NULL; + + sock0 = PR_ImportTCPSocket(osfd); + if (sock0 == NULL) + return set_nspr_error(NULL); + sock = SSL_ImportFD(NULL, sock0); + if (sock == NULL) { + set_nspr_error(NULL); + PR_Close(sock0); + return NULL; + } + + if (PR_GetSockName(sock, &addr) != PR_SUCCESS) { + set_nspr_error(NULL); + goto error; + } + if ((return_value = SSLSocket_new_from_prfiledesc(sock, + PR_NetAddrFamily(&addr))) + == NULL) + goto error; + + return return_value; + + error: + PR_Close(sock); + return NULL; +} + + +static PyMethodDef SSLSocket_methods[] = { + {"set_ssl_option", (PyCFunction)SSLSocket_set_ssl_option, METH_VARARGS, SSLSocket_set_ssl_option_doc}, + {"get_ssl_option", (PyCFunction)SSLSocket_get_ssl_option, METH_VARARGS, SSLSocket_get_ssl_option_doc}, + {"accept", (PyCFunction)SSLSocket_accept, METH_VARARGS|METH_KEYWORDS, SSLSocket_accept_doc}, + {"set_auth_certificate_callback", (PyCFunction)SSLSocket_set_auth_certificate_callback, METH_VARARGS, SSLSocket_set_auth_certificate_callback_doc}, + {"set_client_auth_data_callback", (PyCFunction)SSLSocket_set_client_auth_data_callback, METH_VARARGS, SSLSocket_set_client_auth_data_callback_doc}, + {"set_handshake_callback", (PyCFunction)SSLSocket_set_handshake_callback, METH_VARARGS, SSLSocket_set_handshake_callback_doc}, + {"set_pkcs11_pin_arg", (PyCFunction)SSLSocket_set_pkcs11_pin_arg, METH_VARARGS, SSLSocket_set_pkcs11_pin_arg_doc}, + {"get_pkcs11_pin_arg", (PyCFunction)SSLSocket_get_pkcs11_pin_arg, METH_NOARGS, SSLSocket_get_pkcs11_pin_arg_doc}, + {"config_secure_server", (PyCFunction)SSLSocket_config_secure_server, METH_VARARGS, SSLSocket_config_secure_server_doc}, + {"get_peer_certificate", (PyCFunction)SSLSocket_get_peer_certificate, METH_VARARGS, SSLSocket_get_peer_certificate_doc}, + {"get_certificate", (PyCFunction)SSLSocket_get_certificate, METH_VARARGS, SSLSocket_get_certificate_doc}, + {"invalidate_session", (PyCFunction)SSLSocket_invalidate_session, METH_NOARGS, SSLSocket_invalidate_session_doc}, + {"data_pending", (PyCFunction)SSLSocket_data_pending, METH_NOARGS, SSLSocket_data_pending_doc}, + {"get_security_status", (PyCFunction)SSLSocket_get_security_status, METH_NOARGS, SSLSocket_get_security_status_doc}, + {"get_session_id", (PyCFunction)SSLSocket_get_session_id, METH_NOARGS, SSLSocket_get_session_id_doc}, + {"set_sock_peer_id", (PyCFunction)SSLSocket_set_sock_peer_id, METH_VARARGS, SSLSocket_set_sock_peer_id_doc}, + {"set_cipher_pref", (PyCFunction)SSLSocket_set_cipher_pref, METH_VARARGS, SSLSocket_set_cipher_pref_doc}, + {"get_cipher_pref", (PyCFunction)SSLSocket_get_cipher_pref, METH_VARARGS, SSLSocket_get_cipher_pref_doc}, + {"set_hostname", (PyCFunction)SSLSocket_set_hostname, METH_VARARGS, SSLSocket_set_hostname_doc}, + {"get_hostname", (PyCFunction)SSLSocket_get_hostname, METH_NOARGS, SSLSocket_get_hostname_doc}, + {"set_certificate_db", (PyCFunction)SSLSocket_set_certificate_db, METH_VARARGS, SSLSocket_set_certificate_db_doc}, + {"reset_handshake", (PyCFunction)SSLSocket_reset_handshake, METH_VARARGS, SSLSocket_reset_handshake_doc}, + {"force_handshake", (PyCFunction)SSLSocket_force_handshake, METH_NOARGS, SSLSocket_force_handshake_doc}, + {"force_handshake_timeout", (PyCFunction)SSLSocket_force_handshake_timeout, METH_VARARGS, SSLSocket_force_handshake_timeout_doc}, + {"rehandshake", (PyCFunction)SSLSocket_rehandshake, METH_VARARGS, SSLSocket_rehandshake_doc}, + {"rehandshake_timeout", (PyCFunction)SSLSocket_rehandshake_timeout, METH_VARARGS, SSLSocket_rehandshake_timeout_doc}, + {"import_tcp_socket", (PyCFunction)SSLSocket_import_tcp_socket, METH_VARARGS|METH_STATIC, SSLSocket_import_tcp_socket_doc}, + {NULL, NULL} /* Sentinel */ +}; + + +/* =========================== Class Construction =========================== */ + +static PyObject * +SSLSocket_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + SSLSocket *self; + + TraceObjNewEnter("SSLSocket_new", type); + + if ((self = (SSLSocket *)SocketType.tp_new(type, args, kwds)) == NULL) + return NULL; + + self->auth_certificate_callback = NULL; + self->auth_certificate_callback_data = NULL; + self->pk11_pin_args = NULL; + self->handshake_callback = NULL; + self->handshake_callback_data = NULL; + self->client_auth_data_callback = NULL; + self->client_auth_data_callback_data = NULL; + + TraceObjNewLeave("SSLSocket_new", self); + return (PyObject *)self; +} + +static void +SSLSocket_dealloc(SSLSocket* self) +{ + + TraceMethodEnter("SSLSocket_dealloc", self); + + Py_XDECREF(self->auth_certificate_callback); + Py_XDECREF(self->auth_certificate_callback_data); + Py_XDECREF(self->pk11_pin_args); + Py_XDECREF(self->handshake_callback); + Py_XDECREF(self->handshake_callback_data); + Py_XDECREF(self->client_auth_data_callback); + Py_XDECREF(self->client_auth_data_callback_data); + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(SSLSocket_doc, +"SSLSocket(family=PR_AF_INET, type=PR_DESC_SOCKET_TCP)\n\ +\n\ +\n\ +:Parameters:\n\ + family : integer\n\ + one of:\n\ + - PR_AF_INET\n\ + - PR_AF_INET6\n\ + - PR_AF_LOCAL\n\ + type : integer\n\ + one of:\n\ + - PR_DESC_SOCKET_TCP\n\ + - PR_DESC_SOCKET_UDP\n\ +\n\ +Create a new NSPR SSL socket:\n\ +\n\ +"); + +static int +SSLSocket_init(SSLSocket *self, PyObject *args, PyObject *kwds) +{ + PRFileDesc *ssl_socket = NULL; + + TraceMethodEnter("SSLSocket_init", self); + + if (SocketType.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + + if ((ssl_socket = SSL_ImportFD(NULL, self->pr_socket)) == NULL) { + set_nspr_error(NULL); + return -1; + } + + assert(self->pr_socket == ssl_socket); + TraceMethodLeave("SSLSocket_init", self); + return 0; +} + +PyTypeObject SSLSocketType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.ssl.SSLSocket", /* tp_name */ + sizeof(SSLSocket), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)SSLSocket_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + SSLSocket_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + SSLSocket_methods, /* tp_methods */ + SSLSocket_members, /* tp_members */ + SSLSocket_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)SSLSocket_init, /* tp_init */ + 0, /* tp_alloc */ + SSLSocket_new, /* tp_new */ +}; + +/* ========================================================================== */ +/* ================================= Module ================================= */ +/* ========================================================================== */ + +/* ============================== Module Methods ============================= */ + + +PyDoc_STRVAR(NSS_init_doc, +"nss_init(cert_dir)\n\ +\n\ +:Parameters:\n\ + cert_dir : string\n\ + Pathname of the directory where the certificate, key, and\n\ + security module databases reside.\n\ +\n\ +Sets up configuration files and performs other tasks required to run\n\ +Network Security Services.\n\ +"); + +static PyObject * +NSS_init(PyObject *self, PyObject *args) +{ + char *cert_dir; + + if (!PyArg_ParseTuple(args, "s:nss_init", &cert_dir)) { + return NULL; + } + + if (NSS_Init(cert_dir) != SECSuccess) { + return set_nspr_error(NULL); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(NSS_shutdown_doc, +"nss_shutdown()\n\ +\n\ +Closes the key and certificate databases that were opened by nss_init().\n\ +\n\ +Note that if any reference to an NSS object is leaked (for example, if an SSL\n\ +client application doesn't call clear_session_cache() first) then nss_shutdown fails\n\ +with the error code SEC_ERROR_BUSY.\n\ +"); + +static PyObject * +NSS_shutdown(PyObject *self, PyObject *args) +{ + if (NSS_Shutdown() != SECSuccess) { + return set_nspr_error(NULL); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSL_set_ssl_default_option_doc, +"set_ssl_default_option(option, value)\n\ +\n\ +Changes the default value of a specified SSL option for all\n\ +subsequently opened sockets as long as the current application program\n\ +is running. Refer to the documentation for SSLSocket.set_ssl_option()\n\ +for an explanation of the possible values.\n\ +"); + +static PyObject * +SSL_set_ssl_default_option(PyObject *self, PyObject *args) +{ + int option; + int value; + + if (!PyArg_ParseTuple(args, "ii:set_ssl_default_option", &option, &value)) { + return NULL; + } + + if (SSL_OptionSetDefault(option, value) != SECSuccess) { + return set_nspr_error(NULL); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSL_get_ssl_default_option_doc, +"get_ssl_default_option(value)\n\ +\n\ +Gets the default value of a specified SSL option for all\n\ +subsequently opened sockets as long as the current application program\n\ +is running. Refer to the documentation for SSLSocket.set_ssl_option()\n\ +for an explanation of the possible values.\n\ +"); + +static PyObject * +SSL_get_ssl_default_option(PyObject *self, PyObject *args) +{ + int option; + int value; + + if (!PyArg_ParseTuple(args, "i:get_ssl_default_option", &option)) { + return NULL; + } + + if (SSL_OptionGetDefault(option, &value) != SECSuccess) { + return set_nspr_error(NULL); + } + return PyInt_FromLong(value); +} + +PyDoc_STRVAR(SSL_set_default_cipher_pref_doc, +"set_cipher_pref(cipher, enabled)\n\ +\n\ +:Parameters:\n\ + cipher : integer\n\ + The cipher suite enumeration (e.g. SSL_RSA_WITH_NULL_MD5, etc.)\n\ + enabled : bool\n\ + Boolean value\n\ +\n\ +Sets the application default preference for the specified SSL2, SSL3,\n\ +or TLS cipher. A cipher suite is used only if the policy allows it and\n\ +the preference for it is set to True.\n\ +\n\ +This function must be called once for each cipher you want to enable\n\ +or disable by default.\n\ +\n\ +Note, which cipher suites are permitted or disallowed are modified by\n\ +previous calls to one or more of the SSL Export Policy Functions.\n\ +" +); + +static PyObject * +SSL_set_default_cipher_pref(PyObject *self, PyObject *args) +{ + int cipher; + int enabled; + + if (!PyArg_ParseTuple(args, "ii:set_default_cipher_pref", &cipher, &enabled)) + return NULL; + + if (SSL_CipherPrefSetDefault(cipher, enabled) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSL_get_default_cipher_pref_doc, +"get_default_cipher_pref(cipher) -> enabled\n\ +\n\ +:Parameters:\n\ + cipher : integer\n\ + The cipher suite enumeration (e.g. SSL_RSA_WITH_NULL_MD5, etc.)\n\ +\n\ +Returns the application default preference for the specified SSL2,\n\ +SSL3, or TLS cipher.\n\ +"); + +static PyObject * +SSL_get_default_cipher_pref(PyObject *self, PyObject *args) +{ + int cipher; + int enabled; + + if (!PyArg_ParseTuple(args, "i:get_default_cipher_pref", &cipher)) + return NULL; + + if (SSL_CipherPrefGetDefault(cipher, &enabled) != SECSuccess) + return set_nspr_error(NULL); + + if (enabled) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(SSL_set_cipher_policy_doc, +"set_cipher_pref(cipher, enabled)\n\ +\n\ +:Parameters:\n\ + cipher : integer\n\ + The cipher suite enumeration (e.g. SSL_RSA_WITH_NULL_MD5, etc.)\n\ + enabled : bool\n\ + Boolean value\n\ +\n\ +Tells the SSL library that the specified cipher suite is allowed by\n\ +the application's export license, or is not allowed by the\n\ +application's export license, or is allowed to be used only with a\n\ +Step-Up certificate. It overrides the factory default policy for that\n\ +cipher suite. The default policy for all cipher suites is\n\ +SSL_NOT_ALLOWED, meaning that the application's export license does\n\ +not approve the use of this cipher suite. A U.S.domestic version of a\n\ +product typically sets all cipher suites to SSL_ALLOWED. This setting\n\ +is used to separate export and domestic versions of a product, and is\n\ +not intended to express user cipher preferences.\n\ +"); + +static PyObject * +SSL_set_cipher_policy(PyObject *self, PyObject *args) +{ + int cipher; + int policy; + + if (!PyArg_ParseTuple(args, "ii:set_cipher_policy", &cipher, &policy)) + return NULL; + + if (SSL_CipherPolicySet(cipher, policy) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSL_get_cipher_policy_doc, +"get_cipher_policy(cipher) -> policy\n\ +\n\ +:Parameters:\n\ + cipher : integer\n\ + The cipher suite enumeration (e.g. SSL_RSA_WITH_NULL_MD5, etc.)\n\ +\n\ +Returns the cipher policy." +); + +static PyObject * +SSL_get_cipher_policy(PyObject *self, PyObject *args) +{ + int cipher; + int policy; + + if (!PyArg_ParseTuple(args, "i:get_cipher_policy", &cipher)) + return NULL; + + if (SSL_CipherPolicyGet(cipher, &policy) != SECSuccess) + return set_nspr_error(NULL); + + + if (policy) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(SSL_config_server_session_id_cache_doc, +"config_server_session_id_cache([max_cache_entries=0, ssl2_timeout=0, ssl3_timeout=0, directory=None])\n\ +\n\ +:Parameters:\n\ + max_cache_entries : integer\n\ + The maximum number of entries in the cache. If ZERO the server\n\ + default value is used (10,000).\n\ + \n\ + ssl2_timeout : integer\n\ + The lifetime in seconds of an SSL2 session. The minimum timeout\n\ + value is 5 seconds and the maximum is 24 hours. Values outside\n\ + this range are replaced by the server default value (100 seconds).\n\ + \n\ + ssl3_timeout : integer\n\ + The lifetime in seconds of an SSL3 session. The minimum timeout\n\ + value is 5 seconds and the maximum is 24 hours. Values outside\n\ + this range are replaced by the server default value (24 hours).\n\ + \n\ + directory : string\n\ + A string specifying the pathname of the directory that will\n\ + contain the session cache. If None the server default value is\n\ + used (/tmp (Unix) or \\temp (NT)).\n\ +\n\ +If you are writing an application which will use SSL sockets to\n\ +handshake as a server, you must call config_server_session_id_cache()\n\ +to configure the session caches for server sessions.\n\ +\n\ +If your server application uses multiple processes (instead of or in\n\ +addition to multiple threads), use config_mp_server_sid_cache()\n\ +instead. You must use one of these functions to create a server\n\ +cache.\n\ +\n\ +This function creates two caches: the server session ID cache (also\n\ +called the server session cache, or server cache), and the client-auth\n\ +certificate cache (also called the client cert cache, or client auth\n\ +cache). Both caches are used only for sessions where the program will\n\ +handshakes as a server. The client-auth certificate cache is used to\n\ +remember the certificates previously presented by clients for client\n\ +certificate authentication.\n\ +\n\ +A zero value or a value that is out of range for any of the parameters\n\ +causes the server default value to be used in the server cache. Note,\n\ +this function only affects the server cache, not the client cache.\n\ +"); + + +static PyObject * +SSL_config_server_session_id_cache(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"max_cache_entries", "ssl2_timeout", "ssl3_timeout", "directory", NULL}; + int max_cache_entries = 0; + PRUint32 ssl2_timeout = 0; + PRUint32 ssl3_timeout = 0; + char *directory = NULL; + + TraceMethodEnter("config_server_session_id_cache", self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iIIz:config_server_session_id_cache", kwlist, + &max_cache_entries, &ssl2_timeout, &ssl3_timeout, &directory)) + return NULL; + + if (SSL_ConfigServerSessionIDCache(max_cache_entries, ssl2_timeout, + ssl3_timeout, directory) != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(SSL_clear_session_cache_doc, +"clear_session_cache()\n\ +\n\ +You must call ssl.clear_session_cache() after you use one of the SSL\n\ +Export Policy Functions to change cipher suite policy settings or use\n\ +ssl.set_default_cipher_pref() to enable or disable any cipher\n\ +suite. Otherwise, the old settings remain in the session cache and\n\ +will be used instead of the new settings. This function clears only\n\ +the client cache. The client cache is not configurable. It is located\n\ +in RAM (not on disk).\n\ +"); + +static PyObject * +SSL_clear_session_cache(PyObject *self, PyObject *args) +{ + SSL_ClearSessionCache(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(NSS_set_domestic_policy_doc, +"set_domestic_policy()\n\ +\n\ +Configures cipher suites to conform with current U.S. export\n\ +regulations related to domestic software products with encryption\n\ +features.\n\ +"); + +static PyObject * +NSS_set_domestic_policy(PyObject *self, PyObject *args) +{ + if (NSS_SetDomesticPolicy() != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(NSS_set_export_policy_doc, +"set_export_policy()\n\ +\n\ +Configures the SSL cipher suites to conform with current U.S. export\n\ +regulations related to international software products with encryption\n\ +features.\n\ +"); + +static PyObject * +NSS_set_export_policy(PyObject *self, PyObject *args) +{ + if (NSS_SetExportPolicy() != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(NSS_set_france_policy_doc, +"set_france_policy()\n\ +Configures the SSL cipher suites to conform with French import\n\ +regulations related to software products with encryption features.\n\ +\n\ +"); + +static PyObject * +NSS_set_france_policy(PyObject *self, PyObject *args) +{ + if (NSS_SetFrancePolicy() != SECSuccess) + return set_nspr_error(NULL); + + Py_RETURN_NONE; +} + +/* List of functions exported by this module. */ +static PyMethodDef module_methods[] = { +{"nss_init", (PyCFunction)NSS_init, METH_VARARGS, NSS_init_doc}, +{"nss_shutdown", (PyCFunction)NSS_shutdown, METH_NOARGS, NSS_shutdown_doc}, +{"set_ssl_default_option", (PyCFunction)SSL_set_ssl_default_option, METH_VARARGS, SSL_set_ssl_default_option_doc}, +{"get_ssl_default_option", (PyCFunction)SSL_get_ssl_default_option, METH_VARARGS, SSL_get_ssl_default_option_doc}, +{"set_default_cipher_pref", (PyCFunction)SSL_set_default_cipher_pref, METH_VARARGS, SSL_set_default_cipher_pref_doc}, +{"get_default_cipher_pref", (PyCFunction)SSL_get_default_cipher_pref, METH_VARARGS, SSL_get_default_cipher_pref_doc}, +{"set_cipher_policy", (PyCFunction)SSL_set_cipher_policy, METH_VARARGS, SSL_set_cipher_policy_doc}, +{"get_cipher_policy", (PyCFunction)SSL_get_cipher_policy, METH_VARARGS, SSL_get_cipher_policy_doc}, +{"config_server_session_id_cache", (PyCFunction)SSL_config_server_session_id_cache, METH_VARARGS|METH_KEYWORDS, SSL_config_server_session_id_cache_doc}, +{"clear_session_cache", (PyCFunction)SSL_clear_session_cache, METH_NOARGS, SSL_clear_session_cache_doc}, +{"set_domestic_policy", (PyCFunction)NSS_set_domestic_policy, METH_NOARGS, NSS_set_domestic_policy_doc}, +{"set_export_policy", (PyCFunction)NSS_set_export_policy, METH_NOARGS, NSS_set_export_policy_doc}, +{"set_france_policy", (PyCFunction)NSS_set_france_policy, METH_NOARGS, NSS_set_france_policy_doc}, +{NULL, NULL} /* Sentinel */ +}; + +/* ============================== Module Construction ============================= */ + +PyDoc_STRVAR(module_doc, +"This module implements the SSL functionality in NSS"); + +PyMODINIT_FUNC +initssl(void) +{ + PyObject *m; + int i; + + + if (import_nspr_error_c_api() < 0) + return; + + if (import_nspr_io_c_api() < 0) + return; + + if (import_nspr_nss_c_api() < 0) + return; + + SSLSocketType.tp_base = &SocketType; + if (PyType_Ready(&SSLSocketType) < 0) + return; + + if ((m = Py_InitModule3("nss.ssl", module_methods, module_doc)) == NULL) + return; + + Py_INCREF(&SSLSocketType); + PyModule_AddObject(m, "SSLSocket", (PyObject *)&SSLSocketType); + + /* SSL_ImplementedCiphers */ + if ((py_ssl_implemented_ciphers = PyTuple_New(SSL_NumImplementedCiphers)) == NULL) + return; + + for (i = 0; i < SSL_NumImplementedCiphers; i++) { + PyTuple_SetItem(py_ssl_implemented_ciphers, i, PyInt_FromLong(SSL_ImplementedCiphers[i])); + } + + PyModule_AddObject(m, "ssl_implemented_ciphers", py_ssl_implemented_ciphers); + + /* NSS SSL Constants */ + AddIntConstant(SSL_SECURITY); + AddIntConstant(SSL_SOCKS); + AddIntConstant(SSL_REQUEST_CERTIFICATE); + AddIntConstant(SSL_HANDSHAKE_AS_CLIENT); + AddIntConstant(SSL_HANDSHAKE_AS_SERVER); + AddIntConstant(SSL_ENABLE_SSL2); + AddIntConstant(SSL_ENABLE_SSL3); + AddIntConstant(SSL_NO_CACHE); + AddIntConstant(SSL_REQUIRE_CERTIFICATE); + AddIntConstant(SSL_ENABLE_FDX); + AddIntConstant(SSL_V2_COMPATIBLE_HELLO); + AddIntConstant(SSL_ENABLE_TLS); + AddIntConstant(SSL_ROLLBACK_DETECTION); + AddIntConstant(SSL_NO_STEP_DOWN); + AddIntConstant(SSL_BYPASS_PKCS11); + AddIntConstant(SSL_NO_LOCKS); + + /* Values for "policy" argument to SSL_PolicySet and returned by SSL_CipherPolicyGet. */ + AddIntConstant(SSL_NOT_ALLOWED); + AddIntConstant(SSL_ALLOWED); + AddIntConstant(SSL_RESTRICTED); + + /* Values for "on" with SSL_REQUIRE_CERTIFICATE.*/ + AddIntConstant(SSL_REQUIRE_NEVER); + AddIntConstant(SSL_REQUIRE_ALWAYS); + AddIntConstant(SSL_REQUIRE_FIRST_HANDSHAKE); + AddIntConstant(SSL_REQUIRE_NO_ERROR); + + /* Values for "on" with SSL_SecurityStatus. */ + AddIntConstant(SSL_SECURITY_STATUS_NOOPT); + AddIntConstant(SSL_SECURITY_STATUS_OFF); + AddIntConstant(SSL_SECURITY_STATUS_ON_HIGH); + AddIntConstant(SSL_SECURITY_STATUS_ON_LOW); + + /* Cipher enables. */ + AddIntConstant(SSL_EN_RC4_128_WITH_MD5); + AddIntConstant(SSL_EN_RC4_128_EXPORT40_WITH_MD5); + AddIntConstant(SSL_EN_RC2_128_CBC_WITH_MD5); + AddIntConstant(SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5); + AddIntConstant(SSL_EN_IDEA_128_CBC_WITH_MD5); + AddIntConstant(SSL_EN_DES_64_CBC_WITH_MD5); + AddIntConstant(SSL_EN_DES_192_EDE3_CBC_WITH_MD5); + + /* SSL v3 Cipher Suites */ + AddIntConstant(SSL_NULL_WITH_NULL_NULL); + + AddIntConstant(SSL_RSA_WITH_NULL_MD5); + AddIntConstant(SSL_RSA_WITH_NULL_SHA); + AddIntConstant(SSL_RSA_EXPORT_WITH_RC4_40_MD5); + AddIntConstant(SSL_RSA_WITH_RC4_128_MD5); + AddIntConstant(SSL_RSA_WITH_RC4_128_SHA); + AddIntConstant(SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5); + AddIntConstant(SSL_RSA_WITH_IDEA_CBC_SHA); + AddIntConstant(SSL_RSA_EXPORT_WITH_DES40_CBC_SHA); + AddIntConstant(SSL_RSA_WITH_DES_CBC_SHA); + AddIntConstant(SSL_RSA_WITH_3DES_EDE_CBC_SHA); + + AddIntConstant(SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(SSL_RSA_FIPS_WITH_DES_CBC_SHA); + + AddIntConstant(SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA); + AddIntConstant(SSL_DH_DSS_WITH_DES_CBC_SHA); + AddIntConstant(SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA); + AddIntConstant(SSL_DH_RSA_WITH_DES_CBC_SHA); + AddIntConstant(SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA); + + AddIntConstant(SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA); + AddIntConstant(SSL_DHE_DSS_WITH_DES_CBC_SHA); + AddIntConstant(SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA); + AddIntConstant(SSL_DHE_RSA_WITH_DES_CBC_SHA); + AddIntConstant(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA); + + AddIntConstant(SSL_DH_ANON_EXPORT_WITH_RC4_40_MD5); + AddIntConstant(SSL_DH_ANON_WITH_RC4_128_MD5); + AddIntConstant(SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA); + AddIntConstant(SSL_DH_ANON_WITH_DES_CBC_SHA); + AddIntConstant(SSL_DH_ANON_WITH_3DES_EDE_CBC_SHA); + +/* New TLS cipher suites */ + AddIntConstant(TLS_RSA_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_DH_DSS_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_DH_RSA_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_DHE_DSS_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_DHE_RSA_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_DH_ANON_WITH_AES_128_CBC_SHA); + + AddIntConstant(TLS_RSA_WITH_AES_256_CBC_SHA); + AddIntConstant(TLS_DH_DSS_WITH_AES_256_CBC_SHA); + AddIntConstant(TLS_DH_RSA_WITH_AES_256_CBC_SHA); + AddIntConstant(TLS_DHE_DSS_WITH_AES_256_CBC_SHA); + AddIntConstant(TLS_DHE_RSA_WITH_AES_256_CBC_SHA); + AddIntConstant(TLS_DH_ANON_WITH_AES_256_CBC_SHA); + + AddIntConstant(TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA); + AddIntConstant(TLS_RSA_EXPORT1024_WITH_RC4_56_SHA); + + AddIntConstant(TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA); + AddIntConstant(TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA); + AddIntConstant(TLS_DHE_DSS_WITH_RC4_128_SHA); + + AddIntConstant(TLS_ECDH_ECDSA_WITH_NULL_SHA); + AddIntConstant(TLS_ECDH_ECDSA_WITH_RC4_128_SHA); + AddIntConstant(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA); + + AddIntConstant(TLS_ECDHE_ECDSA_WITH_NULL_SHA); + AddIntConstant(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA); + AddIntConstant(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA); + + AddIntConstant(TLS_ECDH_RSA_WITH_NULL_SHA); + AddIntConstant(TLS_ECDH_RSA_WITH_RC4_128_SHA); + AddIntConstant(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA); + + AddIntConstant(TLS_ECDHE_RSA_WITH_NULL_SHA); + AddIntConstant(TLS_ECDHE_RSA_WITH_RC4_128_SHA); + AddIntConstant(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA); + + AddIntConstant(TLS_ECDH_anon_WITH_NULL_SHA); + AddIntConstant(TLS_ECDH_anon_WITH_RC4_128_SHA); + AddIntConstant(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA); + AddIntConstant(TLS_ECDH_anon_WITH_AES_128_CBC_SHA); + AddIntConstant(TLS_ECDH_anon_WITH_AES_256_CBC_SHA); + +} diff --git a/mozilla/security/python/nss/src/py_ssl.h b/mozilla/security/python/nss/src/py_ssl.h new file mode 100644 index 00000000000..dab1e7ed7ce --- /dev/null +++ b/mozilla/security/python/nss/src/py_ssl.h @@ -0,0 +1,55 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is a Python binding for Network Security Services (NSS). + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * (Author: John Dennis ) + * + * Portions created by the Initial Developer are Copyright (C) 2008,2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#undef HAVE_LONG_LONG /* FIXME: both Python.h and nspr.h define HAVE_LONG_LONG */ +#include "nss.h" +#include "ssl.h" + +typedef struct { + SOCKET_HEAD; + PyObject *auth_certificate_callback; + PyObject *auth_certificate_callback_data; + PyObject *pk11_pin_args; + PyObject *handshake_callback; + PyObject *handshake_callback_data; + PyObject *client_auth_data_callback; + PyObject *client_auth_data_callback_data; +} SSLSocket; + +#define PySSLSocket_Check(op) PyObject_TypeCheck(op, &SSLSocketType) +extern PyTypeObject SSLSocketType; +