diff --git a/mozilla/security/python/nss/MANIFEST b/mozilla/security/python/nss/MANIFEST index c6a67e26530..bf46e3f2717 100644 --- a/mozilla/security/python/nss/MANIFEST +++ b/mozilla/security/python/nss/MANIFEST @@ -9,6 +9,7 @@ doc/examples/cert_dump.py doc/examples/httplib_example.py doc/examples/ssl_example.py doc/examples/verify_server.py +doc/examples/verify_cert.py test/run_tests test/setup_certs.py test/test_cert_components.py diff --git a/mozilla/security/python/nss/doc/ChangeLog b/mozilla/security/python/nss/doc/ChangeLog index e9afaf6fe5a..04742437100 100644 --- a/mozilla/security/python/nss/doc/ChangeLog +++ b/mozilla/security/python/nss/doc/ChangeLog @@ -1,3 +1,130 @@ +2012-10-24 John Dennis 0.14 + External Changes: + ----------------- + + The primary enhancement in this version is support of certifcate + validation, especially CA certs which can be done via + Certificate.verify() or Certificate.is_ca_cert(). When cert + validation fails you can now obtain diagnostic information as to why + the cert failed to validate. This is encapsulated in the + CertVerifyLog class which is a iterable collection of + CertVerifyLogNode objects. Most people will probablby just print the + string representation of the returned CertVerifyLog object. Cert + validation logging is handled by the Certificate.verify() method. + Support has also been added for the various key usage and cert type + entities which feature prominently during cert validation. + + * The following classes were added: + - nss.CertVerifyLogNode + - nss.CertVerifyLog + - error.CertVerifyError (exception) + + * The following class methods were added: + - nss.Certificate.is_ca_cert + - nss.Certificate.verify + - nss.Certificate.verify_with_log + - nss.Certificate.get_cert_chain + - nss.PK11Slot.list_certs + - nss.CertVerifyLogNode.format_lines + - nss.CertVerifyLog.format_lines + + * The following class properties were added: + - nss.CertVerifyLogNode.certificate + - nss.CertVerifyLogNode.error + - nss.CertVerifyLogNode.depth + - nss.CertVerifyLog.count + + * The following module functions were added: + - nss.x509_cert_type + - nss.key_usage_flags + - nss.list_certs + - nss.find_certs_from_email_addr + - nss.find_certs_from_nickname + - nss.get_use_pkix_for_validation + - nss.set_use_pkix_for_validation + + * The following files were added: + doc/examples/verify_cert.py + + * The following constants were added: + - nss.KU_DIGITAL_SIGNATURE + - nss.KU_NON_REPUDIATION + - nss.KU_KEY_ENCIPHERMENT + - nss.KU_DATA_ENCIPHERMENT + - nss.KU_KEY_AGREEMENT + - nss.KU_KEY_CERT_SIGN + - nss.KU_CRL_SIGN + - nss.KU_ENCIPHER_ONLY + - nss.KU_ALL + - nss.KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION + - nss.KU_KEY_AGREEMENT_OR_ENCIPHERMENT + - nss.KU_NS_GOVT_APPROVED + - nss.PK11CertListUnique + - nss.PK11CertListUser + - nss.PK11CertListRootUnique + - nss.PK11CertListCA + - nss.PK11CertListCAUnique + - nss.PK11CertListUserUnique + - nss.PK11CertListAll + - nss.certUsageSSLClient + - nss.certUsageSSLServer + - nss.certUsageSSLServerWithStepUp + - nss.certUsageSSLCA + - nss.certUsageEmailSigner + - nss.certUsageEmailRecipient + - nss.certUsageObjectSigner + - nss.certUsageUserCertImport + - nss.certUsageVerifyCA + - nss.certUsageProtectedObjectSigner + - nss.certUsageStatusResponder + - nss.certUsageAnyCA + + * cert_dump.py extended to print NS_CERT_TYPE_EXTENSION + + * cert_usage_flags, nss_init_flags now support optional repr_kind parameter + + * error codes and descriptions were updated from upstream NSPR & NSS. + + Internal Changes: + ----------------- + + * Reimplement exception handling + - NSPRError is now derived from StandardException instead of + EnvironmentError. It was never correct to derive from + EnvironmentError but was difficult to implement a new subclassed + exception with it's own attributes, using EnvironmentError had + been expedient. + + - NSPRError now derived from StandardException, provides: + * errno (numeric error code) + * strerror (error description associated with error code) + * error_message (optional detailed message) + * error_code (alias for errno) + * error_desc (alias for strerror) + + - CertVerifyError derived from NSPRError, extends with: + * usages (bitmask of returned usages) + * log (CertVerifyLog object) + + * Expose error lookup to sibling modules + + * Use macros for bitmask_to_list functions to reduce code + duplication and centralize logic. + + * Add repr_kind parameter to cert_trust_flags_str() + + * Add support for repr_kind AsEnumName to bitstring table lookup. + + * Add cert_type_bitstr_to_tuple() lookup function + + * Add PRTimeConvert(), used to convert Python time values + to PRTime, centralizes conversion logic, reduces duplication + + * Add Certificate_summary_format_lines() utility to generate + concise certificate identification info for output. + + + 2012-10-05 John Dennis 0.13 * Fix NSS SECITEM_CompareItem bug via workaround. diff --git a/mozilla/security/python/nss/doc/examples/cert_dump.py b/mozilla/security/python/nss/doc/examples/cert_dump.py index 9b181d4bd72..4b314e8bd3f 100755 --- a/mozilla/security/python/nss/doc/examples/cert_dump.py +++ b/mozilla/security/python/nss/doc/examples/cert_dump.py @@ -38,6 +38,10 @@ def print_extension(level, extension): print nss.indented_format([(level, 'Usages:')]) print nss.indented_format(nss.make_line_fmt_tuples(level+1, nss.x509_key_usage(extension.value))) + elif oid_tag == nss.SEC_OID_NS_CERT_EXT_CERT_TYPE: + print nss.indented_format([(level, 'Types:')]) + print nss.indented_format(nss.make_line_fmt_tuples(level+1, nss.x509_cert_type(extension.value))) + elif oid_tag == nss.SEC_OID_X509_SUBJECT_KEY_ID: print nss.indented_format([(level, 'Data:')]) print nss.indented_format(nss.make_line_fmt_tuples(level+1, diff --git a/mozilla/security/python/nss/doc/examples/verify_cert.py b/mozilla/security/python/nss/doc/examples/verify_cert.py new file mode 100755 index 00000000000..876f539e366 --- /dev/null +++ b/mozilla/security/python/nss/doc/examples/verify_cert.py @@ -0,0 +1,278 @@ +#!/usr/bin/python + +import sys +import optparse + +import nss.nss as nss +import nss.error as nss_error + +''' +This example illustrates how one can use NSS to verify (validate) a +certificate. Certificate validation starts with an intended usage for +the certificate and returns a set of flags for which the certificate +is actually valid for. When a cert fails validation it can be +useful to obtain diagnostic information as to why. One of the +verification methods includes returning the diagnostic information in +what is called a log. A cert can also be checked to see if it +qualifies as a CA cert. + +The actual code to verify the cert is simple and straight forward. The +complexity in this example derives mainly from handling all the +options necessary to make the example flexible. + +* The certificate may either be read from a file or loaded by nickname + from a NSS database. + +* You can optionally print the details the cert. + +* You can specify a set of intened cert usages (each -u option adds an + other usage to the set). + +* You can enable/disable checking the cert signature. + +* You can enable/disable using the log variant. + +* You can enable/disable verifying the cert's CA status. + +* The results are pretty printed. + +''' + +#------------------------------------------------------------------------------- +cert_usage_map = { + 'CheckAllUsages' : nss.certificateUsageCheckAllUsages, + 'SSLClient' : nss.certificateUsageSSLClient, + 'SSLServer' : nss.certificateUsageSSLServer, + 'SSLServerWithStepUp' : nss.certificateUsageSSLServerWithStepUp, + 'SSLCA' : nss.certificateUsageSSLCA, + 'EmailSigner' : nss.certificateUsageEmailSigner, + 'EmailRecipient' : nss.certificateUsageEmailRecipient, + 'ObjectSigner' : nss.certificateUsageObjectSigner, + 'UserCertImport' : nss.certificateUsageUserCertImport, + 'VerifyCA' : nss.certificateUsageVerifyCA, + 'ProtectedObjectSigner' : nss.certificateUsageProtectedObjectSigner, + 'StatusResponder' : nss.certificateUsageStatusResponder, + 'AnyCA' : nss.certificateUsageAnyCA, +} + +#------------------------------------------------------------------------------- + +def password_callback(slot, retry, password): + return options.db_passwd + +def indented_output(msg, l, level=0): + msg = '%s:' % msg + lines = [] + if not l: + l = ['--'] + lines.extend(nss.make_line_fmt_tuples(level, msg)) + lines.extend(nss.make_line_fmt_tuples(level+1, l)) + return nss.indented_format(lines) + +def indented_obj(msg, obj, level=0): + msg = '%s:' % msg + lines = [] + lines.extend(nss.make_line_fmt_tuples(level, msg)) + lines.extend(obj.format_lines(level+1)) + return nss.indented_format(lines) + + +#------------------------------------------------------------------------------- + +def main(): + # Command line argument processing + parser = optparse.OptionParser() + + parser.set_defaults(dbdir = '/etc/pki/nssdb', + db_passwd = 'db_passwd', + input_format = 'pem', + check_sig = True, + print_cert = False, + with_log = True, + check_ca = True, + ) + + param_group = optparse.OptionGroup(parser, 'NSS Database', + 'Specify & control the NSS Database') + + param_group.add_option('-d', '--dbdir', dest='dbdir', + help='NSS database directory, default="%default"') + param_group.add_option('-P', '--db-passwd', dest='db_passwd', + help='NSS database password, default="%default"') + + param_group = optparse.OptionGroup(parser, 'Certificate', + 'Specify how the certificate is loaded') + + param_group.add_option('-f', '--file', dest='cert_filename', + help='read cert from file') + param_group.add_option('--format', dest='input_format', choices=['pem', 'der'], + help='import format for certificate (der|pem) default="%default"') + param_group.add_option('-n', '--nickname', dest='cert_nickname', + help='load cert from NSS database by looking it up under this nickname') + + + param_group = optparse.OptionGroup(parser, 'Validation', + 'Control the validation') + + param_group.add_option('-u', '--usage', dest='cert_usage', action='append', choices=cert_usage_map.keys(), + help='may be specified multiple times, default="CheckAllUsages", may be one of: %s' % ', '.join(sorted(cert_usage_map.keys()))) + param_group.add_option('-c', '--check-sig', action='store_true', dest='check_sig', + help='check signature default=%default') + param_group.add_option('-C', '--no-check-sig', action='store_false', dest='check_sig', + help='check signature') + param_group.add_option('-l', '--log', action='store_true', dest='with_log', + help='use verify log, default=%default') + param_group.add_option('-L', '--no-log', action='store_false', dest='with_log', + help='use verify log, default=%default') + param_group.add_option('-a', '--check-ca', action='store_true', dest='check_ca', + help='check if cert is CA, default=%default') + param_group.add_option('-A', '--no-check-ca', action='store_false', dest='check_ca', + help='check if cert is CA, default=%default') + + param_group = optparse.OptionGroup(parser, 'Miscellaneous', + 'Miscellaneous options') + + param_group.add_option('-p', '--print-cert', action='store_true', dest='print_cert', + help='print the certificate in a friendly fashion, default=%default') + + options, args = parser.parse_args() + + # Process the command line arguments + + # Get usage bitmask + if options.cert_usage: + intended_usage = 0 + for usage in options.cert_usage: + try: + flag = cert_usage_map[usage] + except KeyError: + print "Unknown usage '%s', valid values: %s" % (usage, ', '.join(sorted(cert_usage_map.keys()))) + return 1 + else: + intended_usage |= flag + else: + # We can't use nss.certificateUsageCheckAllUsages here because + # it's a special value of zero instead of being the bitwise OR + # of all the certificateUsage* flags (go figure!) + intended_usage = 0 + for usage in cert_usage_map.values(): + intended_usage |= usage + + if options.cert_filename and options.cert_nickname: + print >>sys.stderr, "You may not specify both a cert filename and a nickname, only one or the other" + return 1 + + if not options.cert_filename and not options.cert_nickname: + print >>sys.stderr, "You must specify either a cert filename or a nickname to load" + return 1 + + # Initialize NSS. + print indented_output('NSS Database', options.dbdir) + print + nss.nss_init(options.dbdir) + certdb = nss.get_default_certdb() + nss.set_password_callback(password_callback) + + # Load the cert + if options.cert_filename: + # Read the certificate as DER encoded data then initialize a Certificate from the DER data + filename = options.cert_filename + si = nss.read_der_from_file(filename, options.input_format.lower() == 'pem') + # Parse the DER encoded data returning a Certificate object + cert = nss.Certificate(si) + else: + try: + cert = nss.find_cert_from_nickname(options.cert_nickname) + except Exception, e: + print e + print >>sys.stderr, 'Unable to load cert nickname "%s" from database "%s"' % \ + (options.cert_nickname, options.dbdir) + return 1 + + # Dump the cert if the user wants to see it + if options.print_cert: + print cert + else: + print indented_output('cert subject', cert.subject) + print + + # Dump the usages attached to the cert + print indented_output('cert has these usages', nss.cert_type_flags(cert.cert_type)) + + # Should we check if the cert is a CA cert? + if options.check_ca: + # CA Cert? + is_ca, cert_type = cert.is_ca_cert(True) + print + print indented_output('is CA cert boolean', is_ca) + print indented_output('is CA cert returned usages', nss.cert_type_flags(cert_type)) + + print + print indented_output('verifying usages for', nss.cert_usage_flags(intended_usage)) + print + + # Use the log or non-log variant to verify the cert + # + # Note: Anytime a NSPR or NSS function returns an error in python-nss it + # raises a NSPRError exception. When an exception is raised the normal + # return values are discarded because the flow of control continues at + # the first except block prepared to catch the exception. Normally this + # is what is desired because the return values would be invalid due to + # the error. However the certificate verification functions are an + # exception (no pun intended). An error might be returned indicating the + # cert failed verification but you may still need access to the returned + # usage bitmask and the log (if using the log variant). To handle this a + # special error exception `CertVerifyError` (derived from `NSPRError`) + # is defined which in addition to the normal NSPRError fields will also + # contain the returned usages and optionally the CertVerifyLog + # object. If no exception is raised these are returned as normal return + # values. + + approved_usage = 0 + if options.with_log: + try: + approved_usage, log = cert.verify_with_log(certdb, options.check_sig, intended_usage, None) + except nss_error.CertVerifyError, e: + # approved_usage and log available in CertVerifyError exception on failure. + print e + print + print indented_obj('log', e.log) + print + print indented_output('approved usages from exception', nss.cert_usage_flags(e.usages)) + approved_usage = e.usages # Get the returned usage bitmask from the exception + except Exception, e: + print e + else: + print indented_output('approved usages', nss.cert_usage_flags(approved_usage)) + if log.count: + print + print indented_obj('log', log) + else: + try: + approved_usage = cert.verify(certdb, options.check_sig, intended_usage, None) + except nss_error.CertVerifyError, e: + # approved_usage available in CertVerifyError exception on failure. + print e + print indented_output('approved usages from exception', nss.cert_usage_flags(e.usages)) + approved_usage = e.usages # Get the returned usage bitmask from the exception + except Exception, e: + print e + else: + print indented_output('approved usages', nss.cert_usage_flags(approved_usage)) + + # The cert is valid if all the intended usages are in the approved usages + valid = (intended_usage & approved_usage) == intended_usage + + print + if valid: + print indented_output('SUCCESS: cert is approved for', nss.cert_usage_flags(intended_usage)) + return 0 + else: + print indented_output('FAIL: cert not approved for', nss.cert_usage_flags(intended_usage ^ approved_usage)) + return 1 + +#------------------------------------------------------------------------------- +if __name__ == "__main__": + sys.exit(main()) + + diff --git a/mozilla/security/python/nss/setup.py b/mozilla/security/python/nss/setup.py index 5c936d425d3..5ec2b0317e0 100644 --- a/mozilla/security/python/nss/setup.py +++ b/mozilla/security/python/nss/setup.py @@ -17,7 +17,7 @@ from distutils.util import subst_vars, change_root from distutils.command.build_py import build_py as _build_py from distutils.command.sdist import sdist as _sdist -version = "0.13" +version = "0.14.0alpha" doc_manifest = [ [['include README LICENSE* doc/ChangeLog', @@ -369,7 +369,7 @@ def main(argv): author_email = 'jdennis@redhat.com', maintainer = 'John Dennis', maintainer_email = 'jdennis@redhat.com', - license = 'MPLv1.1 or GPLv2+ or LGPLv2+', + license = 'MPLv2.0 or GPLv2+ or LGPLv2+', platforms = 'posix', url = 'http://www.mozilla.org/projects/security/pki/python-nss', download_url = '', diff --git a/mozilla/security/python/nss/src/NSPRerrs.h b/mozilla/security/python/nss/src/NSPRerrs.h index c70ca620363..44fa4d6bcae 100644 --- a/mozilla/security/python/nss/src/NSPRerrs.h +++ b/mozilla/security/python/nss/src/NSPRerrs.h @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + /* General NSPR 2.0 errors */ /* Caller must #include "prerror.h" */ diff --git a/mozilla/security/python/nss/src/SECerrs.h b/mozilla/security/python/nss/src/SECerrs.h index c17079d4e45..ce890d31f35 100644 --- a/mozilla/security/python/nss/src/SECerrs.h +++ b/mozilla/security/python/nss/src/SECerrs.h @@ -483,7 +483,75 @@ 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.") +"Configured OCSP responder's certificate is invalid.") ER3(SEC_ERROR_OCSP_BAD_SIGNATURE, (SEC_ERROR_BASE + 157), "OCSP response has an invalid signature.") + +ER3(SEC_ERROR_OUT_OF_SEARCH_LIMITS, (SEC_ERROR_BASE + 158), +"Cert validation search is out of search limits") + +ER3(SEC_ERROR_INVALID_POLICY_MAPPING, (SEC_ERROR_BASE + 159), +"Policy mapping contains anypolicy") + +ER3(SEC_ERROR_POLICY_VALIDATION_FAILED, (SEC_ERROR_BASE + 160), +"Cert chain fails policy validation") + +ER3(SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, (SEC_ERROR_BASE + 161), +"Unknown location type in cert AIA extension") + +ER3(SEC_ERROR_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 162), +"Server returned bad HTTP response") + +ER3(SEC_ERROR_BAD_LDAP_RESPONSE, (SEC_ERROR_BASE + 163), +"Server returned bad LDAP response") + +ER3(SEC_ERROR_FAILED_TO_ENCODE_DATA, (SEC_ERROR_BASE + 164), +"Failed to encode data with ASN1 encoder") + +ER3(SEC_ERROR_BAD_INFO_ACCESS_LOCATION, (SEC_ERROR_BASE + 165), +"Bad information access location in cert extension") + +ER3(SEC_ERROR_LIBPKIX_INTERNAL, (SEC_ERROR_BASE + 166), +"Libpkix internal error occurred during cert validation.") + +ER3(SEC_ERROR_PKCS11_GENERAL_ERROR, (SEC_ERROR_BASE + 167), +"A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.") + +ER3(SEC_ERROR_PKCS11_FUNCTION_FAILED, (SEC_ERROR_BASE + 168), +"A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.") + +ER3(SEC_ERROR_PKCS11_DEVICE_ERROR, (SEC_ERROR_BASE + 169), +"A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.") + +ER3(SEC_ERROR_BAD_INFO_ACCESS_METHOD, (SEC_ERROR_BASE + 170), +"Unknown information access method in certificate extension.") + +ER3(SEC_ERROR_CRL_IMPORT_FAILED, (SEC_ERROR_BASE + 171), +"Error attempting to import a CRL.") + +ER3(SEC_ERROR_EXPIRED_PASSWORD, (SEC_ERROR_BASE + 172), +"The password expired.") + +ER3(SEC_ERROR_LOCKED_PASSWORD, (SEC_ERROR_BASE + 173), +"The password is locked.") + +ER3(SEC_ERROR_UNKNOWN_PKCS11_ERROR, (SEC_ERROR_BASE + 174), +"Unknown PKCS #11 error.") + +ER3(SEC_ERROR_BAD_CRL_DP_URL, (SEC_ERROR_BASE + 175), +"Invalid or unsupported URL in CRL distribution point name.") + +ER3(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, (SEC_ERROR_BASE + 176), +"The certificate was signed using a signature algorithm that is disabled because it is not secure.") + +#ifdef SEC_ERROR_LEGACY_DATABASE +ER3(SEC_ERROR_LEGACY_DATABASE, (SEC_ERROR_BASE + 177), +"The certificate/key database is in an old, unsupported format.") +#endif + +#ifdef SEC_ERROR_APPLICATION_CALLBACK_ERROR +ER3(SEC_ERROR_APPLICATION_CALLBACK_ERROR, (SEC_ERROR_BASE + 178), +"The certificate was rejected by extra checks in the application.") +#endif + diff --git a/mozilla/security/python/nss/src/SSLerrs.h b/mozilla/security/python/nss/src/SSLerrs.h index 06ce766e413..b0cb8888d5c 100644 --- a/mozilla/security/python/nss/src/SSLerrs.h +++ b/mozilla/security/python/nss/src/SSLerrs.h @@ -20,7 +20,8 @@ ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3, 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_UNUSED_5, SSL_ERROR_BASE + 5, +"Unrecognized SSL error code.") ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6, "The server has encountered bad data from the client.") @@ -34,7 +35,8 @@ ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8, ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9, "Peer using unsupported version of security protocol.") -/* unused (SSL_ERROR_BASE + 10),*/ +ER3(SSL_ERROR_UNUSED_10, SSL_ERROR_BASE + 10, +"Unrecognized SSL error code.") 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.") @@ -42,9 +44,8 @@ ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11, 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_POST_WARNING, SSL_ERROR_BASE + 13, +"Unrecognized SSL error code.") ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14), "Peer only supports SSL version 2, which is locally disabled.") @@ -71,7 +72,6 @@ ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20), 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.") @@ -285,7 +285,7 @@ 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.") +"Cannot perform the operation until the handshake is complete.") ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87), "Received incorrect handshakes hash values from peer.") @@ -352,3 +352,61 @@ ER3(SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT , (SSL_ERROR_BASE + 107), ER3(SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT , (SSL_ERROR_BASE + 108), "SSL peer reported bad certificate hash value.") + +ER3(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 109), +"SSL received an unexpected New Session Ticket handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 110), +"SSL received a malformed New Session Ticket handshake message.") + +ER3(SSL_ERROR_DECOMPRESSION_FAILURE, (SSL_ERROR_BASE + 111), +"SSL received a compressed record that could not be decompressed.") + +ER3(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, (SSL_ERROR_BASE + 112), +"Renegotiation is not allowed on this SSL socket.") + +ER3(SSL_ERROR_UNSAFE_NEGOTIATION, (SSL_ERROR_BASE + 113), +"Peer attempted old style (potentially vulnerable) handshake.") + +ER3(SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD, (SSL_ERROR_BASE + 114), +"SSL received an unexpected uncompressed record.") + +ER3(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY, (SSL_ERROR_BASE + 115), +"SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.") + +ER3(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID, (SSL_ERROR_BASE + 116), +"SSL received invalid NPN extension data.") + +ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2, (SSL_ERROR_BASE + 117), +"SSL feature not supported for SSL 2.0 connections.") + +ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS, (SSL_ERROR_BASE + 118), +"SSL feature not supported for servers.") + +ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS, (SSL_ERROR_BASE + 119), +"SSL feature not supported for clients.") + +#ifdef SSL_ERROR_INVALID_VERSION_RANGE +ER3(SSL_ERROR_INVALID_VERSION_RANGE, (SSL_ERROR_BASE + 120), +"SSL version range is not valid.") +#endif + +#ifdef SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION +ER3(SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION, (SSL_ERROR_BASE + 121), +"SSL peer selected a cipher suite disallowed for the selected protocol version.") +#endif + +#ifdef SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST +ER3(SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 122), +"SSL received a malformed Hello Verify Request handshake message.") +#endif + +#ifdef SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 123), +"SSL received an unexpected Hello Verify Request handshake message.") +#endif + +#ifdef SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION +ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION, (SSL_ERROR_BASE + 124), +"SSL feature not supported for the protocol version.") +#endif diff --git a/mozilla/security/python/nss/src/__init__.py b/mozilla/security/python/nss/src/__init__.py index 24f2732be91..d45504f5de3 100644 --- a/mozilla/security/python/nss/src/__init__.py +++ b/mozilla/security/python/nss/src/__init__.py @@ -312,5 +312,5 @@ FAQ To be added """ -__version__ = '0.13' +__version__ = '0.14.0alpha' diff --git a/mozilla/security/python/nss/src/py_nspr_common.h b/mozilla/security/python/nss/src/py_nspr_common.h index 23e31ac0808..bfa60d48ca9 100644 --- a/mozilla/security/python/nss/src/py_nspr_common.h +++ b/mozilla/security/python/nss/src/py_nspr_common.h @@ -68,6 +68,8 @@ typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t); #define PyNone_Check(x) ((x) == Py_None) +#define CALL_BASE(type, func, ...) (type)->tp_base->tp_##func(__VA_ARGS__) + #define TYPE_READY(type) \ { \ if (PyType_Ready(&type) < 0) \ diff --git a/mozilla/security/python/nss/src/py_nspr_error.c b/mozilla/security/python/nss/src/py_nspr_error.c index 3e781ff6678..b9452d06b53 100644 --- a/mozilla/security/python/nss/src/py_nspr_error.c +++ b/mozilla/security/python/nss/src/py_nspr_error.c @@ -8,15 +8,7 @@ #define NSS_ERROR_MODULE #include "py_nspr_error.h" - - -static PyObject *NSPR_Exception = NULL; - -typedef struct { - PRErrorCode num; - const char *name; - const char *string; -} NSPRErrorDesc; +#include "py_nspr_common.h" #include "nspr.h" #include "seccomon.h" @@ -27,7 +19,26 @@ typedef struct { #include "secerr.h" #include "sslerr.h" +typedef struct { + PyBaseExceptionObject base; + PyObject *error_desc; + PyObject *error_message; + PyObject *str_value; + int error_code; +} NSPRError; + +typedef struct { + NSPRError base; + PyObject *log; + unsigned int usages; +} CertVerifyError; + +static PyObject *empty_tuple = NULL; +static PyTypeObject NSPRErrorType; +static PyTypeObject CertVerifyErrorType; + NSPRErrorDesc nspr_errors[] = { + {0, "SUCCESS", "Success"}, #include "SSLerrs.h" #include "SECerrs.h" #include "NSPRerrs.h" @@ -46,6 +57,23 @@ cmp_error(const void *p1, const void *p2) const int nspr_error_count = sizeof(nspr_errors) / sizeof(NSPRErrorDesc); +static int +IntOrNoneConvert(PyObject *obj, int *param) +{ + if (PyInt_Check(obj)) { + *param = PyInt_AsLong(obj); + return 1; + } + + if (PyNone_Check(obj)) { + return 1; + } + + PyErr_Format(PyExc_TypeError, "must be int or None, not %.50s", + Py_TYPE(obj)->tp_name); + return 0; +} + static PRStatus init_nspr_errors(void) { int low = 0; @@ -102,36 +130,31 @@ lookup_nspr_error(PRErrorCode num) { } static PyObject * -set_nspr_error(const char *format, ...) +get_error_desc(PRErrorCode *p_error_code) { - va_list vargs; - PyObject *v; - const NSPRErrorDesc *error_desc; - char *pr_err_msg=NULL; + PRErrorCode error_code = 0; + NSPRErrorDesc const *error_desc = NULL; + char *pr_err_msg = NULL; PRInt32 pr_err_msg_len; - PRErrorCode error_code; - PyObject *detail = NULL; - char *final_err_msg=NULL; + char *final_err_msg = NULL; + PyObject *result = NULL; - if (format) { -#ifdef HAVE_STDARG_PROTOTYPES - va_start(vargs, format); -#else - va_start(vargs); -#endif - detail = PyString_FromFormatV(format, vargs); - va_end(vargs); - } - - error_code = PR_GetError(); - error_desc = lookup_nspr_error(error_code); - - if ((pr_err_msg_len = PR_GetErrorTextLength())) { - if ((pr_err_msg = PyMem_Malloc(pr_err_msg_len + 1))) { - PR_GetErrorText(pr_err_msg); + if (!p_error_code || *p_error_code == -1) { + error_code = PR_GetError(); + if (p_error_code) { + *p_error_code = error_code; } + if ((pr_err_msg_len = PR_GetErrorTextLength())) { + if ((pr_err_msg = PyMem_Malloc(pr_err_msg_len + 1))) { + PR_GetErrorText(pr_err_msg); + } + } + } else { + error_code = *p_error_code; } + error_desc = lookup_nspr_error(error_code); + if (pr_err_msg && error_desc) { final_err_msg = PR_smprintf("%s (%s) %s", pr_err_msg, error_desc->name, error_desc->string); } else if (error_desc) { @@ -142,23 +165,97 @@ set_nspr_error(const char *format, ...) final_err_msg = PR_smprintf("error (%d) unknown", error_code); } - if (detail) { - v = Py_BuildValue("(isS)", error_code, final_err_msg, detail); - Py_DECREF(detail); - } else { - v = Py_BuildValue("(is)", error_code, final_err_msg); - } - if (v != NULL) { - PyErr_SetObject(NSPR_Exception, v); - Py_DECREF(v); - } + result = PyString_FromString(final_err_msg); if (final_err_msg) PR_smprintf_free(final_err_msg); if (pr_err_msg) PyMem_Free(pr_err_msg); + return result; +} + +static PyObject * +set_nspr_error(const char *format, ...) +{ + va_list vargs; + PyObject *error_message = NULL; + PyObject *kwds = NULL; + PyObject *exception_obj = NULL; + + if (format) { +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + error_message = PyString_FromFormatV(format, vargs); + va_end(vargs); + } + + if ((kwds = PyDict_New()) == NULL) { + return NULL; + } + + if (error_message) { + if (PyDict_SetItemString(kwds, "error_message", error_message) != 0) { + return NULL; + } + } + + exception_obj = PyObject_Call((PyObject *)&NSPRErrorType, empty_tuple, kwds); + Py_DECREF(kwds); + + PyErr_SetObject((PyObject *)&NSPRErrorType, exception_obj); + return NULL; } +static PyObject * +set_cert_verify_error(unsigned int usages, PyObject *log, const char *format, ...) +{ + va_list vargs; + PyObject *error_message = NULL; + PyObject *kwds = NULL; + PyObject *exception_obj = NULL; + + if (format) { +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + error_message = PyString_FromFormatV(format, vargs); + va_end(vargs); + } + + if ((kwds = PyDict_New()) == NULL) { + return NULL; + } + + if (error_message) { + if (PyDict_SetItemString(kwds, "error_message", error_message) != 0) { + return NULL; + } + } + + if (PyDict_SetItemString(kwds, "usages", PyInt_FromLong(usages)) != 0) { + return NULL; + } + + if (log) { + if (PyDict_SetItemString(kwds, "log", log) != 0) { + return NULL; + } + } + + exception_obj = PyObject_Call((PyObject *)&CertVerifyErrorType, empty_tuple, kwds); + Py_DECREF(kwds); + + PyErr_SetObject((PyObject *)&CertVerifyErrorType, exception_obj); + + return NULL; +} + + PyDoc_STRVAR(io_get_nspr_error_string_doc, "get_nspr_error_string(number) -> string\n\ \n\ @@ -291,13 +388,422 @@ static PyObject *tuple_str(PyObject *tuple) return text; } +/* ========================================================================== */ +/* ========================= NSPRError Class ========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + + +static PyMemberDef NSPRError_members[] = { + {"errno", T_INT, offsetof(NSPRError, error_code), READONLY, + PyDoc_STR("NSS error code")}, + {"error_code", T_INT, offsetof(NSPRError, error_code), READONLY, + PyDoc_STR("NSS error code")}, + + {"strerror", T_OBJECT, offsetof(NSPRError, error_desc), READONLY, + PyDoc_STR("NSS error code description")}, + {"error_desc", T_OBJECT, offsetof(NSPRError, error_desc), READONLY, + PyDoc_STR("NSS error code description")}, + + {"error_message", T_OBJECT, offsetof(NSPRError, error_message), READONLY, + PyDoc_STR("error message specific to this error")}, + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +NSPRError_str(NSPRError *self) +{ + TraceMethodEnter(self); + + Py_XINCREF(self->str_value); + return self->str_value; + +} + +/* =========================== Class Construction =========================== */ + +static int +NSPRError_traverse(NSPRError *self, visitproc visit, void *arg) +{ + Py_VISIT(self->error_desc); + Py_VISIT(self->error_message); + Py_VISIT(self->str_value); + CALL_BASE(&NSPRErrorType, traverse, (PyObject *)self, visit, arg); + + return 0; +} + +static int +NSPRError_clear(NSPRError* self) +{ + TraceMethodEnter(self); + + Py_CLEAR(self->error_desc); + Py_CLEAR(self->error_message); + Py_CLEAR(self->str_value); + CALL_BASE(&NSPRErrorType, clear, (PyObject *)self); + + return 0; +} + +static void +NSPRError_dealloc(NSPRError* self) +{ + TraceMethodEnter(self); + + NSPRError_clear(self); + + Py_TYPE(self)->tp_free((PyObject *)self); +} + +PyDoc_STRVAR(NSPRError_doc, +"NSPRError(error_message=None, error_code=None)\n\ +\n\ +:Parameters:\n\ + error_message : string\n\ + Detail message specific to this error.\n\ + error_code : int\n\ + NSS or NSPR error value, if None get current error\n\ +\n\ +Exception object (derived from StandardException), raised when an\n\ +NSS or NSPR error occurs. The error model in python-nss is anytime\n\ +a NSS or NSPR C function returns an error the python-nss binding\n\n\ +raises a NSPRError exception.\n\ +\n\ +Raised internally, there should be no need to raise this exception\n\ +from with a Python program using python-nss.\n\ +\n\ +The error_message is an optional string detailing the specifics\n\ +of an error.\n\ +\n\ +If the error_code is not passed then the current error is queried.\n\ +\n\ +A NSPRError contains the following attributes:\n\ +\n\ + error_code\n\ + The numeric NSPR or NSS error code (integer).\n\ + If not passed the current NSPR or NSS error for the\n\ + current thread is queried and substituted.\n\ + error_desc\n\ + Error description associated with error code (string).\n\ + error_message\n\ + Optional message with details specific to the error (string).\n\ + errno\n\ + Alias for errno.\n\ + strerr\n\ + Alias for error_desc.\n\ +\n\ +"); + +static int +NSPRError_init(NSPRError *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"error_message", "error_code", NULL}; + const char *error_message = NULL; + int error_code = -1; + PyObject *error_desc = NULL; + PyObject *str_value = NULL; + + TraceMethodEnter(self); + + CALL_BASE(&NSPRErrorType, init, (PyObject *)self, args, NULL); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zO&:NSPRError", kwlist, + &error_message, + IntOrNoneConvert, &error_code)) + return -1; + + error_desc = get_error_desc(&error_code); + + if (error_message) { + str_value = PyString_FromFormat("%s: %s", + error_message, + error_desc ? PyString_AsString(error_desc) : + _("Error description unavailable")); + } else { + str_value = error_desc; + } + + + Py_CLEAR(self->base.message); + self->base.message = str_value; + Py_XINCREF(self->base.message); + + Py_CLEAR(self->str_value); + self->str_value = str_value; + Py_XINCREF(self->str_value); + + Py_CLEAR(self->error_desc); + self->error_desc = error_desc; + Py_XINCREF(self->error_desc); + + self->error_code = error_code; + + return 0; +} + +static PyTypeObject NSPRErrorType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.error.NSPRError", /* tp_name */ + sizeof(NSPRError), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)NSPRError_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)NSPRError_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + NSPRError_doc, /* tp_doc */ + (traverseproc)NSPRError_traverse, /* tp_traverse */ + (inquiry)NSPRError_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + NSPRError_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)NSPRError_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +/* ========================================================================== */ +/* ========================= CertVerifyError Class ========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + + +static PyMemberDef CertVerifyError_members[] = { + {"usages", T_UINT, offsetof(CertVerifyError, usages), READONLY, + PyDoc_STR("usages returned by NSS")}, + {"log", T_OBJECT, offsetof(CertVerifyError, log), READONLY, + PyDoc_STR("verifcation log, see `CertVerifyLog`")}, + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +CertVerifyError_str(CertVerifyError *self) +{ + PyObject *super_str = NULL; + PyObject *str = NULL; + + TraceMethodEnter(self); + + if ((super_str = CALL_BASE(&CertVerifyErrorType, str, (PyObject *)self)) == NULL) { + return NULL; + } + + str = PyString_FromFormat("%s usages=%#x", PyString_AsString(super_str), self->usages); + Py_DECREF(super_str); + return str; +} + +/* =========================== Class Construction =========================== */ + +static int +CertVerifyError_traverse(CertVerifyError *self, visitproc visit, void *arg) +{ + Py_VISIT(self->log); + CALL_BASE(&CertVerifyErrorType, traverse, (PyObject *)self, visit, arg); + + return 0; +} + +static int +CertVerifyError_clear(CertVerifyError* self) +{ + TraceMethodEnter(self); + + Py_CLEAR(self->log); + CALL_BASE(&CertVerifyErrorType, clear, (PyObject *)self); + + return 0; +} + +static void +CertVerifyError_dealloc(CertVerifyError* self) +{ + TraceMethodEnter(self); + + CertVerifyError_clear(self); + + Py_TYPE(self)->tp_free((PyObject *)self); +} + +PyDoc_STRVAR(CertVerifyError_doc, +"CertVerifyError(error_message=None, error_code=None, usages=None, log=None)\n\ +\n\ +:Parameters:\n\ + error_message : string\n\ + Detail message specific to this error.\n\ + error_code : int\n\ + NSS or NSPR error value, if None get current error\n\ + usages : int\n\ + The returned usages bitmaks from the verify function.\n\ + log : `CertVerifyLog` object\n\ + The verification log generated during the verification\n\ + operation.\n\ +\n\ +Exception object (derived from NSPRError), raised when an\n\ +error occurs during certificate verification.\n\ +\n\ +Raised internally, there should be no need to raise this exception\n\ +from with a Python program using python-nss.\n\ +\n\ +Certificate verification presents a problem for the normal error\n\ +handling model whereby any error returned from an underlying C\n\ +function causes a `NSPRError` exception to be raised. When an\n\ +exception is raised the return values are lost. It is unusual for a\n\ +function to have useful return values when the function also returns\n\ +an error.\n\ +\n\ +The certificate verification functions are one such example. If\n\ +verification fails useful information concerning validated usages and\n\ +the verification log need to be available. But to be consistent with\n\ +model of always raising an exception on an error return some other\n\ +mechanism is needed to return the extra information. The solution is\n\ +to embed the information which normally would have been in the return\n\ +values in the exception object where it can be queried. The\n\ +CertVerifyError contails the returned usages bitmask and optionally\n\ +the `CertVerifyLog` verification log object if requested.\n\ +\n\ +In addtion to the attributes in a `NSPRError` a CertVerifyError contains\n\ +the following attributes:\n\ +\n\ + usages\n\ + The retured usages bitmask (unsigned int) from the Certificate\n\ + verification function.\n\ + log\n\ + The (optional) `CertVerifyLog` object which contains the\n\ + diagnostic information for why a certificate failed to validate.\n\ +\n\ +"); + +static int +CertVerifyError_init(CertVerifyError *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"error_message", "error_code", "usages", "log", NULL}; + const char *error_message = NULL; + int error_code = -1; + unsigned int usages = 0; + PyObject *log = NULL; + PyObject *super_kwds = NULL; + int result = 0; + + TraceMethodEnter(self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zO&IO:CertVerifyError", kwlist, + &error_message, + IntOrNoneConvert, &error_code, + &usages, + &log)) + return -1; + + if ((super_kwds = PyDict_New()) == NULL) { + return -1; + } + if (error_message) { + if (PyDict_SetItemString(super_kwds, "error_message", PyString_FromString(error_message)) != 0) { + Py_DECREF(super_kwds); + return -1; + } + } + if (error_code != -1) { + if (PyDict_SetItemString(super_kwds, "error_code", PyInt_FromLong(error_code)) != 0) { + Py_DECREF(super_kwds); + return -1; + } + } + if ((result = CertVerifyErrorType.tp_base->tp_init((PyObject *)self, empty_tuple, super_kwds)) != 0) { + Py_DECREF(super_kwds); + return result; + } + + + self->usages = usages; + + Py_CLEAR(self->log); + self->log = log; + Py_XINCREF(self->log); + + return 0; +} + +static PyTypeObject CertVerifyErrorType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.error.CertVerifyError", /* tp_name */ + sizeof(CertVerifyError), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)CertVerifyError_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)CertVerifyError_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + CertVerifyError_doc, /* tp_doc */ + (traverseproc)CertVerifyError_traverse, /* tp_traverse */ + (inquiry)CertVerifyError_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + CertVerifyError_members, /* tp_members */ + 0, /* tp_getset */ + &NSPRErrorType, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)CertVerifyError_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + + /* ============================== Module Exports ============================= */ static PyNSPR_ERROR_C_API_Type nspr_error_c_api = { NULL, /* nspr_exception */ - set_nspr_error, /* set_nspr_error */ - tuple_str + set_nspr_error, + set_cert_verify_error, + tuple_str, + lookup_nspr_error, }; /* ============================== Module Construction ============================= */ @@ -317,6 +823,11 @@ initerror(void) if ((m = Py_InitModule3("error", module_methods, module_doc)) == NULL) return; + if ((empty_tuple = PyTuple_New(0)) == NULL) { + return; + } + Py_INCREF(empty_tuple); + if ((py_error_doc = init_py_nspr_errors(m)) == NULL) return; @@ -326,15 +837,13 @@ initerror(void) PyString_ConcatAndDel(&py_module_doc, py_error_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; + NSPRErrorType.tp_base = (PyTypeObject *)PyExc_StandardError; + + TYPE_READY(NSPRErrorType); + TYPE_READY(CertVerifyErrorType); /* Export C API */ - nspr_error_c_api.nspr_exception = NSPR_Exception; + nspr_error_c_api.nspr_exception = (PyObject *)&NSPRErrorType; 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 index 28cf90890fa..0515eb507bf 100644 --- a/mozilla/security/python/nss/src/py_nspr_error.h +++ b/mozilla/security/python/nss/src/py_nspr_error.h @@ -2,15 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + /* 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 { + PRErrorCode num; + const char *name; + const char *string; +} NSPRErrorDesc; + typedef struct { PyObject *nspr_exception; PyObject *(*set_nspr_error)(const char *format, ...); + PyObject *(*set_cert_verify_error)(unsigned int usages, PyObject * log, const char *format, ...); PyObject *(*tuple_str)(PyObject *tuple); + const NSPRErrorDesc *(*lookup_nspr_error)(PRErrorCode num); } PyNSPR_ERROR_C_API_Type; #ifdef NSS_ERROR_MODULE @@ -20,7 +30,9 @@ typedef struct { static PyNSPR_ERROR_C_API_Type nspr_error_c_api; #define set_nspr_error (*nspr_error_c_api.set_nspr_error) +#define set_cert_verify_error (*nspr_error_c_api.set_cert_verify_error) #define tuple_str (*nspr_error_c_api.tuple_str) +#define lookup_nspr_error (*nspr_error_c_api.lookup_nspr_error) static int import_nspr_error_c_api(void) diff --git a/mozilla/security/python/nss/src/py_nspr_io.c b/mozilla/security/python/nss/src/py_nspr_io.c index 6a46631a715..ab6e50fde85 100644 --- a/mozilla/security/python/nss/src/py_nspr_io.c +++ b/mozilla/security/python/nss/src/py_nspr_io.c @@ -1719,7 +1719,7 @@ Socket_set_socket_option(Socket *self, PyObject *args) { PyObject *py_option = NULL; int option; - int bool; + int boolean; unsigned int uint; NetworkAddress *mcaddr = NULL; NetworkAddress *ifaddr = NULL; @@ -1742,25 +1742,25 @@ Socket_set_socket_option(Socket *self, PyObject *args) switch(option) { case PR_SockOpt_Nonblocking: - if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &boolean)) return NULL; - data.value.non_blocking = bool; + data.value.non_blocking = boolean; break; case PR_SockOpt_Linger: - if (!PyArg_ParseTuple(args, "iiI:set_socket_option", &option, &bool, &uint)) + if (!PyArg_ParseTuple(args, "iiI:set_socket_option", &option, &boolean, &uint)) return NULL; - data.value.linger.polarity = bool; + data.value.linger.polarity = boolean; data.value.linger.linger = uint; break; case PR_SockOpt_Reuseaddr: - if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &boolean)) return NULL; - data.value.reuse_addr = bool; + data.value.reuse_addr = boolean; break; case PR_SockOpt_Keepalive: - if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &boolean)) return NULL; - data.value.keep_alive = bool; + data.value.keep_alive = boolean; break; case PR_SockOpt_RecvBufferSize: if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) @@ -1810,14 +1810,14 @@ Socket_set_socket_option(Socket *self, PyObject *args) data.value.mcast_ttl = uint; break; case PR_SockOpt_McastLoopback: - if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &boolean)) return NULL; - data.value.mcast_loopback = bool; + data.value.mcast_loopback = boolean; break; case PR_SockOpt_NoDelay: - if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &boolean)) return NULL; - data.value.no_delay = bool; + data.value.no_delay = boolean; break; case PR_SockOpt_MaxSegment: if (!PyArg_ParseTuple(args, "iI:set_socket_option", &option, &uint)) @@ -1825,9 +1825,9 @@ Socket_set_socket_option(Socket *self, PyObject *args) data.value.max_segment = uint; break; case PR_SockOpt_Broadcast: - if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &bool)) + if (!PyArg_ParseTuple(args, "ii:set_socket_option", &option, &boolean)) return NULL; - data.value.broadcast = bool; + data.value.broadcast = boolean; break; default: PyErr_SetString(PyExc_ValueError, "set_socket_option: unknown option"); diff --git a/mozilla/security/python/nss/src/py_nss.c b/mozilla/security/python/nss/src/py_nss.c index d1067e05e54..049ddb3affa 100644 --- a/mozilla/security/python/nss/src/py_nss.c +++ b/mozilla/security/python/nss/src/py_nss.c @@ -72,6 +72,52 @@ static PyMemberDef NewType_members[] = { /* ============================== Class Methods ============================= */ +static PyObject * +NewType_format_lines(NewType *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + + SECOidTag alg_tag; + + TraceMethodEnter(self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) { + return NULL; + } + + return lines; + fail: + Py_XDECREF(obj); + Py_XDECREF(lines); + return NULL; +} + +static PyObject * +NewType_format(NewType *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter(self); + + return format_from_lines((format_lines_func)NewType_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +NewType_str(NewType *self) +{ + PyObject *py_formatted_result = NULL; + + TraceMethodEnter(self); + + py_formatted_result = NewType_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + PyDoc_STRVAR(NewType_func_name_doc, "func_name() -> \n\ \n\ @@ -98,10 +144,69 @@ NewType_func_name(PyObject *self, PyObject *args, PyObject *kwds) } static PyMethodDef NewType_methods[] = { - {"func_name", (PyCFunction)NewType_func_name, METH_VARARGS|METH_KEYWORDS, NewType_func_name_doc}, + {"format_lines", (PyCFunction)NewType_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)NewType_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + {"func_name", (PyCFunction)NewType_func_name, METH_VARARGS|METH_KEYWORDS, NewType_func_name_doc}, {NULL, NULL} /* Sentinel */ }; +/* =========================== Sequence Protocol ============================ */ +static Py_ssize_t +NSSType_list_count(NSSType *head) +{ + NSSType *cur; + Py_ssize_t count; + + count = 0; + if (!head) { + return count; + } + + cur = head; + do { + count++; + cur = NSSType_Next(cur); + } while (cur != head); + + return count; +} + +static Py_ssize_t +NewType_length(NewType *self) +{ + if (!self->name) { + PyErr_Format(PyExc_ValueError, "%s is uninitialized", Py_TYPE(self)->tp_name); + return -1; + } + + return NSSType_list_count(self->name); +} + +static PyObject * +NewType_item(NewType *self, register Py_ssize_t i) +{ + NSSType *head, *cur; + Py_ssize_t index; + + if (!self->name) { + return PyErr_Format(PyExc_ValueError, "%s is uninitialized", Py_TYPE(self)->tp_name); + } + + index = 0; + cur = head = self->name; + do { + cur = NSSType_Next(cur); + if (i == index) { + return NewType_new_from_NSSType(cur); + } + index++; + } while (cur != head); + + PyErr_SetString(PyExc_IndexError, "NewType index out of range"); + return NULL; +} + + /* =========================== Class Construction =========================== */ static PyObject * @@ -169,12 +274,18 @@ NewType_init(NewType *self, PyObject *args, PyObject *kwds) return 0; } -static PyObject * -NewType_repr(NewType *self) -{ - return PyString_FromFormat("<%s object at %p>", - Py_TYPE(self)->tp_name, self); -} +static PySequenceMethods NewType_as_sequence = { + (lenfunc)NewType_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)NewType_item, /* 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 NewTypeType = { PyObject_HEAD_INIT(NULL) @@ -187,13 +298,13 @@ static PyTypeObject NewTypeType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - (reprfunc)NewType_repr, /* tp_repr */ + 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ - 0, /* tp_str */ + (reprfunc)NewType_str, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -243,8 +354,6 @@ NewType_new_from_NSSType(NSSType *id) #define CERT_DecodeDERCertificate __CERT_DecodeDERCertificate -#include - #define PY_SSIZE_T_CLEAN #include "Python.h" #include "structmember.h" @@ -283,8 +392,75 @@ NewType_new_from_NSSType(NSSType *id) #define PyRSAGenParams_Check(op) PyObject_TypeCheck(op, &RSAGenParamsType) #define PyKEYPQGParams_Check(op) PyObject_TypeCheck(op, &KEYPQGParamsType) +#define PyCertVerifyLog_Check(op) PyObject_TypeCheck(op, &CertVerifyLogType) +#define BIT_FLAGS_TO_LIST_PROLOGUE() \ + PyObject *py_flags = NULL; \ + PyObject *py_flag = NULL; \ + \ + switch(repr_kind) { \ + case AsEnum: \ + case AsEnumName: \ + case AsEnumDescription: \ + break; \ + default: \ + PyErr_Format(PyExc_ValueError, "Unsupported representation kind (%d)", repr_kind); \ + return NULL; \ + } \ + \ + if ((py_flags = PyList_New(0)) == NULL) \ + return NULL; + + + +#define BIT_FLAGS_TO_LIST(enum, description) \ +{ \ + if (flags & enum) { \ + flags &= ~enum; \ + switch(repr_kind) { \ + case AsEnum: \ + py_flag = PyInt_FromLong(enum); \ + break; \ + case AsEnumName: \ + py_flag = PyString_FromString(#enum); \ + break; \ + case AsEnumDescription: \ + py_flag = PyString_FromString(description); \ + break; \ + default: \ + PyErr_Format(PyExc_ValueError, "Unsupported representation kind (%d)", repr_kind); \ + Py_DECREF(py_flags); \ + return NULL; \ + } \ + if (py_flag == NULL) { \ + Py_DECREF(py_flags); \ + return NULL; \ + } \ + PyList_Append(py_flags, py_flag); \ + Py_DECREF(py_flag); \ + } \ +} + +#define BIT_FLAGS_TO_LIST_EPILOGUE() \ +{ \ + if (flags) { \ + if ((py_flag = PyString_FromFormat("unknown bit flags %#x", flags)) == NULL) { \ + Py_DECREF(py_flags); \ + return NULL; \ + } \ + PyList_Append(py_flags, py_flag); \ + Py_DECREF(py_flag); \ + } \ + \ + if (PyList_Sort(py_flags) == -1) { \ + Py_DECREF(py_flags); \ + return NULL; \ + } \ + \ + return py_flags; \ +} + // FIXME, should use this in more places. PyObject * PyString_UTF8(PyObject *obj, char *name); @@ -1301,6 +1477,7 @@ static PyTypeObject PK11SymKeyType; static PyTypeObject AVAType; static PyTypeObject RDNType; static PyTypeObject DNType; +static PyTypeObject CertVerifyLogType; /* === Forward Declarations */ @@ -1412,7 +1589,7 @@ static PyObject * cert_oid_tag_name(PyObject *self, PyObject *args); static PyObject * -cert_trust_flags_str(unsigned int flags); +cert_trust_flags_str(unsigned int flags, RepresentationKind repr_kind); static PyObject * SecItem_new_from_SECItem(const SECItem *item, SECItemKind kind); @@ -1503,6 +1680,9 @@ SECItem_der_to_hex(SECItem *item, int octets_per_line, char *separator); static PyObject * cert_x509_key_usage(PyObject *self, PyObject *args, PyObject *kwds); +static PyObject * +cert_x509_cert_type(PyObject *self, PyObject *args, PyObject *kwds); + PyObject * CRLDistributionPts_new_from_SECItem(SECItem *item); @@ -1533,6 +1713,15 @@ Certificate_new_from_signed_der_secitem(SECItem *der); static int Certificate_init_from_unsigned_der_secitem(Certificate *self, SECItem *der); +static PyObject * +Certificate_get_subject(Certificate *self, void *closure); + +static PyObject * +Certificate_get_issuer(Certificate *self, void *closure); + +static PyObject * +Certificate_new_from_CERTCertificate(CERTCertificate *cert); + static PyObject * fingerprint_format_lines(SECItem *item, int level); @@ -1542,41 +1731,65 @@ PKCS12Decoder_item(PKCS12Decoder *self, register Py_ssize_t i); PyObject * KEYPQGParams_init_from_SECKEYPQGParams(KEYPQGParams *self, const SECKEYPQGParams *params); +static PyObject * +CertVerifyLog_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static Py_ssize_t +CertVerifyLog_length(CertVerifyLog *self); + +static PyObject * +CertVerifyLog_item(CertVerifyLog *self, register Py_ssize_t i); + /* ==================================== */ typedef struct BitStringTableStr { int enum_value; + const char *enum_name; const char *enum_description; } BitStringTable; +#define BITSTRING_TBL_INIT(enum, description) \ + {enum, #enum, description} + static BitStringTable CRLReasonDef[] = { - {crlEntryReasonUnspecified, _("Unspecified") }, /* bit 0 */ - {crlEntryReasonKeyCompromise, _("Key Compromise") }, /* bit 1 */ - {crlEntryReasonCaCompromise, _("CA Compromise") }, /* bit 2 */ - {crlEntryReasonAffiliationChanged, _("Affiliation Changed") }, /* bit 3 */ - {crlEntryReasonSuperseded, _("Superseded") }, /* bit 4 */ - {crlEntryReasonCessationOfOperation, _("Cessation Of Operation")}, /* bit 5 */ - {crlEntryReasoncertificatedHold, _("Certificate On Hold") }, /* bit 6 */ - {-1, NULL, }, /* bit 7 */ - {crlEntryReasonRemoveFromCRL, _("Remove From CRL") }, /* bit 8 */ - {crlEntryReasonPrivilegeWithdrawn, _("Privilege Withdrawn") }, /* bit 9 */ - {crlEntryReasonAaCompromise, _("AA Compromise") }, /* bit 10 */ + BITSTRING_TBL_INIT(crlEntryReasonUnspecified, _("Unspecified") ), /* bit 0 */ + BITSTRING_TBL_INIT(crlEntryReasonKeyCompromise, _("Key Compromise") ), /* bit 1 */ + BITSTRING_TBL_INIT(crlEntryReasonCaCompromise, _("CA Compromise") ), /* bit 2 */ + BITSTRING_TBL_INIT(crlEntryReasonAffiliationChanged, _("Affiliation Changed") ), /* bit 3 */ + BITSTRING_TBL_INIT(crlEntryReasonSuperseded, _("Superseded") ), /* bit 4 */ + BITSTRING_TBL_INIT(crlEntryReasonCessationOfOperation, _("Cessation Of Operation")), /* bit 5 */ + BITSTRING_TBL_INIT(crlEntryReasoncertificatedHold, _("Certificate On Hold") ), /* bit 6 */ + BITSTRING_TBL_INIT(-1, NULL ), /* bit 7 */ + BITSTRING_TBL_INIT(crlEntryReasonRemoveFromCRL, _("Remove From CRL") ), /* bit 8 */ + BITSTRING_TBL_INIT(crlEntryReasonPrivilegeWithdrawn, _("Privilege Withdrawn") ), /* bit 9 */ + BITSTRING_TBL_INIT(crlEntryReasonAaCompromise, _("AA Compromise") ), /* bit 10 */ }; static BitStringTable KeyUsageDef[] = { - {KU_DIGITAL_SIGNATURE, _("Digital Signature") }, /* bit 0 */ - {KU_NON_REPUDIATION, _("Non-Repudiation") }, /* bit 1 */ - {KU_KEY_ENCIPHERMENT, _("Key Encipherment") }, /* bit 2 */ - {KU_DATA_ENCIPHERMENT, _("Data Encipherment") }, /* bit 3 */ - {KU_KEY_AGREEMENT, _("Key Agreement") }, /* bit 4 */ - {KU_KEY_CERT_SIGN, _("Certificate Signing")}, /* bit 5 */ - {KU_CRL_SIGN, _("CRL Signing") }, /* bit 6 */ - {KU_ENCIPHER_ONLY, _("Encipher Only") }, /* bit 7 */ + BITSTRING_TBL_INIT(KU_DIGITAL_SIGNATURE, _("Digital Signature") ), /* bit 0 */ + BITSTRING_TBL_INIT(KU_NON_REPUDIATION, _("Non-Repudiation") ), /* bit 1 */ + BITSTRING_TBL_INIT(KU_KEY_ENCIPHERMENT, _("Key Encipherment") ), /* bit 2 */ + BITSTRING_TBL_INIT(KU_DATA_ENCIPHERMENT, _("Data Encipherment") ), /* bit 3 */ + BITSTRING_TBL_INIT(KU_KEY_AGREEMENT, _("Key Agreement") ), /* bit 4 */ + BITSTRING_TBL_INIT(KU_KEY_CERT_SIGN, _("Certificate Signing")), /* bit 5 */ + BITSTRING_TBL_INIT(KU_CRL_SIGN, _("CRL Signing") ), /* bit 6 */ + BITSTRING_TBL_INIT(KU_ENCIPHER_ONLY, _("Encipher Only") ), /* bit 7 */ #ifdef KU_DECIPHER_ONLY - {KU_DECIPHER_ONLY, _("Decipher Only") }, /* bit 8 */ + BITSTRING_TBL_INIT(KU_DECIPHER_ONLY, _("Decipher Only") ), /* bit 8 */ #endif }; +static BitStringTable CertTypeDef[] = { + BITSTRING_TBL_INIT(NS_CERT_TYPE_SSL_CLIENT, _("SSL Client") ), /* bit 0 */ + BITSTRING_TBL_INIT(NS_CERT_TYPE_SSL_SERVER, _("SSL Server") ), /* bit 1 */ + BITSTRING_TBL_INIT(NS_CERT_TYPE_EMAIL, _("Email") ), /* bit 2 */ + BITSTRING_TBL_INIT(NS_CERT_TYPE_OBJECT_SIGNING, _("Object Signing") ), /* bit 3 */ + BITSTRING_TBL_INIT(NS_CERT_TYPE_RESERVED, _("Reserved") ), /* bit 4 */ + BITSTRING_TBL_INIT(NS_CERT_TYPE_SSL_CA, _("SSL CA") ), /* bit 5 */ + BITSTRING_TBL_INIT(NS_CERT_TYPE_EMAIL_CA, _("Email CA") ), /* bit 6 */ + BITSTRING_TBL_INIT(NS_CERT_TYPE_OBJECT_SIGNING_CA, _("Object Signing CA") ), /* bit 7 */ +}; + /* returns new reference or NULL on error */ PyObject * PyString_UTF8(PyObject *obj, char *name) @@ -1815,6 +2028,9 @@ bitstr_table_to_tuple(SECItem *bitstr, BitStringTable *table, case AsEnum: PyTuple_SetItem(tuple, j++, PyInt_FromLong(table[i].enum_value)); break; + case AsEnumName: + PyTuple_SetItem(tuple, j++, PyString_FromString(table[i].enum_name)); + break; case AsEnumDescription: PyTuple_SetItem(tuple, j++, PyString_FromString(table[i].enum_description)); break; @@ -1853,6 +2069,15 @@ key_usage_bitstr_to_tuple(SECItem *bitstr, RepresentationKind repr_kind) return bitstr_table_to_tuple(bitstr, KeyUsageDef, table_len, repr_kind); } +static PyObject * +cert_type_bitstr_to_tuple(SECItem *bitstr, RepresentationKind repr_kind) +{ + size_t table_len; + + table_len = sizeof(CertTypeDef) / sizeof(CertTypeDef[0]); + return bitstr_table_to_tuple(bitstr, CertTypeDef, table_len, repr_kind); +} + static PyObject * decode_oid_sequence_to_tuple(SECItem *item, RepresentationKind repr_kind) { @@ -1923,6 +2148,35 @@ decode_oid_sequence_to_tuple(SECItem *item, RepresentationKind repr_kind) return tuple; } +static PyObject * +CERTCertList_to_tuple(CERTCertList *cert_list) +{ + Py_ssize_t n_certs = 0; + Py_ssize_t i = 0; + CERTCertListNode *node = NULL; + PyObject *py_cert = NULL; + PyObject *tuple = NULL; + + for (node = CERT_LIST_HEAD(cert_list), n_certs = 0; + !CERT_LIST_END(node, cert_list); + node = CERT_LIST_NEXT(node), n_certs++); + + if ((tuple = PyTuple_New(n_certs)) == NULL) { + return NULL; + } + + for (node = CERT_LIST_HEAD(cert_list), i = 0; + !CERT_LIST_END(node, cert_list); + node = CERT_LIST_NEXT(node), i++) { + if ((py_cert = Certificate_new_from_CERTCertificate(node->cert)) == NULL) { + Py_DECREF(tuple); + return NULL; + } + PyTuple_SetItem(tuple, i, py_cert); + } + return tuple; +} + /* NSS WART: CERT_CopyAVA is hidden, but we need it, copied here from secname.c */ CERTAVA * CERT_CopyAVA(PRArenaPool *arena, CERTAVA *from) @@ -2661,6 +2915,34 @@ del_thread_local(const char *name) } #endif +static int +PRTimeConvert(PyObject *obj, PRTime *param) +{ + PRTime time; + + if (PyFloat_Check(obj)) { + LL_D2L(time, PyFloat_AsDouble(obj)); + *param = time; + return 1; + } + + if (PyInt_Check(obj)) { + LL_I2L(time, PyInt_AsLong(obj)); /* FIXME: should be PyLong_AsLongLong? */ + *param = time; + return 1; + } + + if (PyNone_Check(obj)) { + time = PR_Now(); + *param = time; + return 1; + } + + PyErr_Format(PyExc_TypeError, "must be int, float or None, not %.50s", + Py_TYPE(obj)->tp_name); + return 0; +} + static int PK11SlotOrNoneConvert(PyObject *obj, PyObject **param) { @@ -4150,376 +4432,117 @@ CERTRDN_to_pystr(CERTRDN *rdn) } static PyObject * -cert_trust_flags_str(unsigned int flags) +cert_trust_flags_str(unsigned int flags, RepresentationKind repr_kind) { - PyObject *py_flags = NULL; - PyObject *py_flag = NULL; - - if ((py_flags = PyList_New(0)) == NULL) - return NULL; + BIT_FLAGS_TO_LIST_PROLOGUE(); #if NSS_VMAJOR >= 3 && NSS_VMINOR >= 13 - if (flags & CERTDB_TERMINAL_RECORD) { - flags &= ~CERTDB_TERMINAL_RECORD; - if ((py_flag = PyString_FromString(_("Terminal Record"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } + BIT_FLAGS_TO_LIST(CERTDB_TERMINAL_RECORD, _("Terminal Record")); #else - if (flags & CERTDB_VALID_PEER) { - flags &= ~CERTDB_VALID_PEER; - if ((py_flag = PyString_FromString(_("Valid Peer"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } + BIT_FLAGS_TO_LIST(CERTDB_VALID_PEER, _("Valid Peer")); #endif - if (flags & CERTDB_TRUSTED) { - flags &= ~CERTDB_TRUSTED; - if ((py_flag = PyString_FromString(_("Trusted"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & CERTDB_SEND_WARN) { - 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); - Py_DECREF(py_flag); - } - if (flags & CERTDB_VALID_CA) { - flags &= ~CERTDB_VALID_CA; - if ((py_flag = PyString_FromString(_("Valid CA"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & CERTDB_TRUSTED_CA) { - flags &= ~CERTDB_TRUSTED_CA; - if ((py_flag = PyString_FromString(_("Trusted CA"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & CERTDB_NS_TRUSTED_CA) { - 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); - Py_DECREF(py_flag); - } - if (flags & CERTDB_USER) { - flags &= ~CERTDB_USER; - if ((py_flag = PyString_FromString(_("User"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & CERTDB_TRUSTED_CLIENT_CA) { - 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); - Py_DECREF(py_flag); - } - if (flags & CERTDB_GOVT_APPROVED_CA) { - 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); - Py_DECREF(py_flag); - } + BIT_FLAGS_TO_LIST(CERTDB_TRUSTED, _("Trusted")); + BIT_FLAGS_TO_LIST(CERTDB_SEND_WARN, _("Warn When Sending")); + BIT_FLAGS_TO_LIST(CERTDB_VALID_CA, _("Valid CA")); + BIT_FLAGS_TO_LIST(CERTDB_TRUSTED_CA, _("Trusted CA")); + BIT_FLAGS_TO_LIST(CERTDB_NS_TRUSTED_CA, _("Netscape Trusted CA")); + BIT_FLAGS_TO_LIST(CERTDB_USER, _("User")); + BIT_FLAGS_TO_LIST(CERTDB_TRUSTED_CLIENT_CA, _("Trusted Client CA")); + BIT_FLAGS_TO_LIST(CERTDB_GOVT_APPROVED_CA, _("Step-up")); - if (flags) { - if ((py_flag = PyString_FromFormat("unknown bit flags %#x", flags)) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - - if (PyList_Sort(py_flags) == -1) { - Py_DECREF(py_flags); - return NULL; - } - - return py_flags; + BIT_FLAGS_TO_LIST_EPILOGUE(); } static PyObject * -cert_usage_flags(unsigned int flags) +cert_usage_flags(unsigned int flags, RepresentationKind repr_kind) { - PyObject *py_flags = NULL; - PyObject *py_flag = NULL; + BIT_FLAGS_TO_LIST_PROLOGUE(); - if ((py_flags = PyList_New(0)) == NULL) - return NULL; + BIT_FLAGS_TO_LIST(certificateUsageSSLClient, _("SSL Client")); + BIT_FLAGS_TO_LIST(certificateUsageSSLServer, _("SSL Server")); + BIT_FLAGS_TO_LIST(certificateUsageSSLServerWithStepUp, _("SSL Server With StepUp")); + BIT_FLAGS_TO_LIST(certificateUsageSSLCA, _("SSL CA")); + BIT_FLAGS_TO_LIST(certificateUsageEmailSigner, _("Email Signer")); + BIT_FLAGS_TO_LIST(certificateUsageEmailRecipient, _("Email Recipient")); + BIT_FLAGS_TO_LIST(certificateUsageObjectSigner, _("Object Signer")); + BIT_FLAGS_TO_LIST(certificateUsageUserCertImport, _("User Certificate Import")); + BIT_FLAGS_TO_LIST(certificateUsageVerifyCA, _("Verify CA")); + BIT_FLAGS_TO_LIST(certificateUsageProtectedObjectSigner, _("Protected Object Signer")); + BIT_FLAGS_TO_LIST(certificateUsageStatusResponder, _("Status Responder")); + BIT_FLAGS_TO_LIST(certificateUsageAnyCA, _("Any CA")); - if (flags & certificateUsageSSLClient) { - flags &= ~certificateUsageSSLClient; - if ((py_flag = PyString_FromString(_("SSLClient"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageSSLServer) { - flags &= ~certificateUsageSSLServer; - if ((py_flag = PyString_FromString(_("SSLServer"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageSSLServerWithStepUp) { - flags &= ~certificateUsageSSLServerWithStepUp; - if ((py_flag = PyString_FromString(_("SSLServerWithStepUp"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageSSLCA) { - flags &= ~certificateUsageSSLCA; - if ((py_flag = PyString_FromString(_("SSLCA"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageEmailSigner) { - flags &= ~certificateUsageEmailSigner; - if ((py_flag = PyString_FromString(_("EmailSigner"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageEmailRecipient) { - flags &= ~certificateUsageEmailRecipient; - if ((py_flag = PyString_FromString(_("EmailRecipient"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageObjectSigner) { - flags &= ~certificateUsageObjectSigner; - if ((py_flag = PyString_FromString(_("ObjectSigner"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageUserCertImport) { - flags &= ~certificateUsageUserCertImport; - if ((py_flag = PyString_FromString(_("UserCertImport"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageVerifyCA) { - flags &= ~certificateUsageVerifyCA; - if ((py_flag = PyString_FromString(_("VerifyCA"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageProtectedObjectSigner) { - flags &= ~certificateUsageProtectedObjectSigner; - if ((py_flag = PyString_FromString(_("ProtectedObjectSigner"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageStatusResponder) { - flags &= ~certificateUsageStatusResponder; - if ((py_flag = PyString_FromString(_("StatusResponder"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & certificateUsageAnyCA) { - flags &= ~certificateUsageAnyCA; - if ((py_flag = PyString_FromString(_("AnyCA"))) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - - if (flags) { - if ((py_flag = PyString_FromFormat("unknown bit flags %#x", flags)) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - - if (PyList_Sort(py_flags) == -1) { - Py_DECREF(py_flags); - return NULL; - } - - return py_flags; + BIT_FLAGS_TO_LIST_EPILOGUE(); } static PyObject * -nss_init_flags(unsigned int flags) +key_usage_flags(unsigned int flags, RepresentationKind repr_kind) { - PyObject *py_flags = NULL; - PyObject *py_flag = NULL; + BIT_FLAGS_TO_LIST_PROLOGUE(); + BIT_FLAGS_TO_LIST(KU_DIGITAL_SIGNATURE, _("Digital Signature")); + BIT_FLAGS_TO_LIST(KU_NON_REPUDIATION, _("Non-Repudiation")); + BIT_FLAGS_TO_LIST(KU_KEY_ENCIPHERMENT, _("Key Encipherment")); + BIT_FLAGS_TO_LIST(KU_DATA_ENCIPHERMENT, _("Data Encipherment")); + BIT_FLAGS_TO_LIST(KU_KEY_AGREEMENT, _("Key Agreement")); + BIT_FLAGS_TO_LIST(KU_KEY_CERT_SIGN, _("Certificate Signing")); + BIT_FLAGS_TO_LIST(KU_CRL_SIGN, _("CRL Signing")); + BIT_FLAGS_TO_LIST(KU_ENCIPHER_ONLY, _("Encipher Only")); +#ifdef KU_DECIPHER_ONLY + BIT_FLAGS_TO_LIST(KU_DECIPHER_ONLY, _("Decipher Only")); +#endif + /* + * The following flags are not present in certs but appear in + * CERTVerifyNode when the error is + * SEC_ERROR_INADEQUATE_KEY_USAGE. This rountine is also used + * to print those flags. + */ + BIT_FLAGS_TO_LIST(KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION, _("Digital Signature or Non-Repudiation")); + BIT_FLAGS_TO_LIST(KU_KEY_AGREEMENT_OR_ENCIPHERMENT, _("Key Agreement or Data Encipherment")); + BIT_FLAGS_TO_LIST(KU_NS_GOVT_APPROVED, _("Government Approved")); - if ((py_flags = PyList_New(0)) == NULL) - return NULL; + BIT_FLAGS_TO_LIST_EPILOGUE(); +} - if (flags & NSS_INIT_READONLY) { - flags &= ~NSS_INIT_READONLY; - if ((py_flag = PyString_FromString("READONLY")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_NOCERTDB) { - flags &= ~NSS_INIT_NOCERTDB; - if ((py_flag = PyString_FromString("NOCERTDB")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_NOMODDB) { - flags &= ~NSS_INIT_NOMODDB; - if ((py_flag = PyString_FromString("NOMODDB")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_FORCEOPEN) { - flags &= ~NSS_INIT_FORCEOPEN; - if ((py_flag = PyString_FromString("FORCEOPEN")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_NOROOTINIT) { - flags &= ~NSS_INIT_NOROOTINIT; - if ((py_flag = PyString_FromString("NOROOTINIT")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_OPTIMIZESPACE) { - flags &= ~NSS_INIT_OPTIMIZESPACE; - if ((py_flag = PyString_FromString("OPTIMIZESPACE")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_PK11THREADSAFE) { - flags &= ~NSS_INIT_PK11THREADSAFE; - if ((py_flag = PyString_FromString("PK11THREADSAFE")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_PK11RELOAD) { - flags &= ~NSS_INIT_PK11RELOAD; - if ((py_flag = PyString_FromString("PK11RELOAD")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_NOPK11FINALIZE) { - flags &= ~NSS_INIT_NOPK11FINALIZE; - if ((py_flag = PyString_FromString("NOPK11FINALIZE")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } - if (flags & NSS_INIT_RESERVED) { - flags &= ~NSS_INIT_RESERVED; - if ((py_flag = PyString_FromString("RESERVED")) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } +static PyObject * +cert_type_flags(unsigned int flags, RepresentationKind repr_kind) +{ + BIT_FLAGS_TO_LIST_PROLOGUE(); - if (flags) { - if ((py_flag = PyString_FromFormat("unknown bit flags %#x", flags)) == NULL) { - Py_DECREF(py_flags); - return NULL; - } - PyList_Append(py_flags, py_flag); - Py_DECREF(py_flag); - } + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_SSL_CLIENT, _("SSL Client")); + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_SSL_SERVER, _("SSL Server")); + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_EMAIL, _("Email")); + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_OBJECT_SIGNING, _("Object Signing")); + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_RESERVED, _("Reserved")); + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_SSL_CA, _("SSL CA")); + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_EMAIL_CA, _("Email CA")); + BIT_FLAGS_TO_LIST(NS_CERT_TYPE_OBJECT_SIGNING_CA, _("Object Signing CA")); + /* + * The following flags are not actual cert types but they get + * OR'ed into a cert type bitmask. + */ + BIT_FLAGS_TO_LIST(EXT_KEY_USAGE_TIME_STAMP, _("Key Usage Timestamp")); + BIT_FLAGS_TO_LIST(EXT_KEY_USAGE_STATUS_RESPONDER, _("Key Usage Status Responder")); - if (PyList_Sort(py_flags) == -1) { - Py_DECREF(py_flags); - return NULL; - } + BIT_FLAGS_TO_LIST_EPILOGUE(); +} - return py_flags; +static PyObject * +nss_init_flags(unsigned int flags, RepresentationKind repr_kind) +{ + BIT_FLAGS_TO_LIST_PROLOGUE(); + + BIT_FLAGS_TO_LIST(NSS_INIT_READONLY, _("Read Only")); + BIT_FLAGS_TO_LIST(NSS_INIT_NOCERTDB, _("No Certificate Database")); + BIT_FLAGS_TO_LIST(NSS_INIT_NOMODDB, _("No Module Database")); + BIT_FLAGS_TO_LIST(NSS_INIT_FORCEOPEN, _("Force Open")); + BIT_FLAGS_TO_LIST(NSS_INIT_NOROOTINIT, _("No Root Init")); + BIT_FLAGS_TO_LIST(NSS_INIT_OPTIMIZESPACE, _("Optimize Space")); + BIT_FLAGS_TO_LIST(NSS_INIT_PK11THREADSAFE, _("PK11 Thread Safe")); + BIT_FLAGS_TO_LIST(NSS_INIT_PK11RELOAD, _("PK11 Reload")); + BIT_FLAGS_TO_LIST(NSS_INIT_NOPK11FINALIZE, _("No PK11 Finalize")); + BIT_FLAGS_TO_LIST(NSS_INIT_RESERVED, _("Reserved")); + + BIT_FLAGS_TO_LIST_EPILOGUE(); } @@ -5161,8 +5184,6 @@ RSAPSSParams_format_lines(SECItem *item, int level) PyObject *obj = NULL; PyObject *obj1 = NULL; - TraceMethodEnter(self); - /* allocate an arena to use */ if ((arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE)) == NULL ) { set_nspr_error(NULL); @@ -5690,7 +5711,7 @@ RSAGenParams_set_key_size(RSAGenParams *self, PyObject *value, void *closure) TraceMethodEnter(self); if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the classproperty attribute"); + PyErr_SetString(PyExc_TypeError, "Cannot delete the key_size attribute"); return -1; } @@ -5720,7 +5741,7 @@ RSAGenParams_set_public_exponent(RSAGenParams *self, PyObject *value, void *clos TraceMethodEnter(self); if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete the classproperty attribute"); + PyErr_SetString(PyExc_TypeError, "Cannot delete the public_exponent attribute"); return -1; } @@ -7880,6 +7901,21 @@ CertificateExtension_format_lines(CertificateExtension *self, PyObject *args, Py APPEND_LINE_TUPLES_AND_CLEAR(lines, obj_lines, fail); break; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + FMT_LABEL_AND_APPEND(lines, _("Types"), level, fail); + if ((tmp_args = Py_BuildValue("(O)", self->py_value)) == NULL) { + goto fail; + } + if ((obj = cert_x509_cert_type(NULL, tmp_args, NULL)) == NULL) { + goto fail; + } + Py_CLEAR(tmp_args); + if ((obj_lines = make_line_fmt_tuples(level+1, obj)) == NULL) { + goto fail; + } + APPEND_LINE_TUPLES_AND_CLEAR(lines, obj_lines, fail); + break; + case SEC_OID_X509_SUBJECT_KEY_ID: FMT_LABEL_AND_APPEND(lines, _("Data"), level, fail); if ((obj_lines = SECItem_der_to_hex(&self->py_value->item, @@ -8259,7 +8295,7 @@ Certificate_get_ssl_trust_str(Certificate *self, void *closure) TraceMethodEnter(self); if (self->cert->trust) - return cert_trust_flags_str(self->cert->trust->sslFlags); + return cert_trust_flags_str(self->cert->trust->sslFlags, AsEnumDescription); else Py_RETURN_NONE; } @@ -8270,7 +8306,7 @@ Certificate_get_email_trust_str(Certificate *self, void *closure) TraceMethodEnter(self); if (self->cert->trust) - return cert_trust_flags_str(self->cert->trust->emailFlags); + return cert_trust_flags_str(self->cert->trust->emailFlags, AsEnumDescription); else Py_RETURN_NONE; } @@ -8281,7 +8317,7 @@ Certificate_get_signing_trust_str(Certificate *self, void *closure) TraceMethodEnter(self); if (self->cert->trust) - return cert_trust_flags_str(self->cert->trust->objectSigningFlags); + return cert_trust_flags_str(self->cert->trust->objectSigningFlags, AsEnumDescription); else Py_RETURN_NONE; } @@ -8330,6 +8366,14 @@ Certificate_get_extensions(Certificate *self, void *closure) return extensions_tuple; } +static PyObject * +Certificate_get_cert_type(Certificate *self, void *closure) +{ + TraceMethodEnter(self); + + return PyInt_FromLong(self->cert->nsCertType); +} + static PyGetSetDef Certificate_getseters[] = { {"valid_not_before", (getter)Certificate_get_valid_not_before, NULL, @@ -8382,6 +8426,10 @@ PyGetSetDef Certificate_getseters[] = { {"extensions", (getter)Certificate_get_extensions, NULL, "certificate extensions as a tuple of CertificateExtension objects", NULL}, + + {"cert_type", (getter)Certificate_get_cert_type, NULL, + "integer bitmask of NS_CERT_TYPE_* flags, see `nss.cert_type_flags()`", NULL}, + {NULL} /* Sentinel */ }; @@ -8574,35 +8622,69 @@ Returns one of:\n\ static PyObject * Certificate_check_valid_times(Certificate *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = {"time", NULL}; - PyObject *py_time = NULL; + static char *kwlist[] = {"time", "allow_override", NULL}; int allow_override = 0; - PRTime time; + PRTime pr_time = 0; SECCertTimeValidity validity; TraceMethodEnter(self); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:check_valid_times", kwlist, &py_time, &allow_override)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&i:check_valid_times", kwlist, + PRTimeConvert, &pr_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(); + if (!pr_time) { + pr_time = PR_Now(); } - validity = CERT_CheckCertValidTimes(self->cert, time, allow_override); + validity = CERT_CheckCertValidTimes(self->cert, pr_time, allow_override); return PyInt_FromLong(validity); } +PyDoc_STRVAR(Certificate_is_ca_cert_doc, +"is_ca_cert(return_cert_type=False) -> boolean\n\ +is_ca_cert(True) -> boolean, cert_type\n\ +\n\ +:Parameters:\n\ + return_cert_type : boolean\n\ + If True returns both boolean result and certficate\n\ + type bitmask. If False return only boolean result\n\ +\n\ +Returns True if the cert is a CA cert, False otherwise.\n\ +\n\ +The function optionally can return a bitmask of NS_CERT_TYPE_*\n\ +flags if return_cert_type is True. This is the updated cert type\n\ +after applying logic in the context of deciding if the cert is a\n\ +CA cert or not. Hint: the cert_type value can be converted to text\n\ +with `nss.cert_type_flags()`. Hint: the unmodified cert type flags\n\ +can be obtained with the `Certificate.cert_type` property.\n\ +\n\ +"); +static PyObject * +Certificate_is_ca_cert(Certificate *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"return_cert_type", NULL}; + int return_cert_type = false; + PRBool is_ca = PR_FALSE; + unsigned int cert_type = 0; + + TraceMethodEnter(self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:is_ca_cert", kwlist, + &return_cert_type)) + return NULL; + + is_ca = CERT_IsCACert(self->cert, return_cert_type ? &cert_type : NULL); + + + if (return_cert_type) { + return Py_BuildValue("NI", PyBool_FromLong(is_ca), cert_type); + } else { + return PyBool_FromLong(is_ca); + } +} + PyDoc_STRVAR(Certificate_verify_now_doc, "verify_now(certdb, check_sig, required_usages, [user_data1, ...]) -> valid_usages\n\ \n\ @@ -8642,6 +8724,9 @@ required usages, otherwise it is for all possible usages.\n\ \n\ Hint: You can obtain a printable representation of the usage flags\n\ via `cert_usage_flags`.\n\ +\n\ +Note: See the `Certificate.verify` documentation for details on how\n\ +the Certificate verification functions handle errors.\n\ "); static PyObject * @@ -8655,7 +8740,7 @@ Certificate_verify_now(Certificate *self, PyObject *args) PyObject *py_check_sig = NULL; PRBool check_sig = 0; long required_usages = 0; - SECCertificateUsage returned_usages; + SECCertificateUsage returned_usages = 0; TraceMethodEnter(self); @@ -8683,7 +8768,7 @@ Certificate_verify_now(Certificate *self, PyObject *args) required_usages, pin_args, &returned_usages) != SECSuccess) { Py_BLOCK_THREADS Py_DECREF(pin_args); - return set_nspr_error(NULL); + return set_cert_verify_error(returned_usages, NULL, NULL); } Py_END_ALLOW_THREADS Py_DECREF(pin_args); @@ -8691,6 +8776,225 @@ Certificate_verify_now(Certificate *self, PyObject *args) return PyInt_FromLong(returned_usages); } +PyDoc_STRVAR(Certificate_verify_doc, +"verify(certdb, check_sig, required_usages, time, [user_data1, ...]) -> 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\ + 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\ + user_dataN : object\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\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.\n\ +\n\ +If required_usages is non-zero, the returned bitmap is only for those\n\ +required usages, otherwise it is for all possible usages.\n\ +\n\ +Hint: You can obtain a printable representation of the usage flags\n\ +via `cert_usage_flags`.\n\ +\n\ +Note: Anytime a NSPR or NSS function returns an error in python-nss it\n\ +raises a NSPRError exception. When an exception is raised the normal\n\ +return values are discarded because the flow of control continues at\n\ +the first except block prepared to catch the exception. Normally this\n\ +is what is desired because the return values would be invalid due to\n\ +the error. However the certificate verification functions are an\n\ +exception (no pun intended). An error might be returned indicating the\n\ +cert failed verification but you may still need access to the returned\n\ +usage bitmask and the log (if using the log variant). To handle this a\n\ +special error exception `CertVerifyError` (derived from `NSPRError`)\n\ +is defined which in addition to the normal NSPRError fields will also\n\ +contain the returned usages and optionally the CertVerifyLog\n\ +object. If no exception is raised these are returned as normal return\n\ +values.\n\ +"); + +static PyObject * +Certificate_verify(Certificate *self, PyObject *args) +{ + Py_ssize_t n_base_args = 4; + Py_ssize_t argc; + PyObject *parse_args = NULL; + PyObject *pin_args = NULL; + CertDB *py_certdb = NULL; + PyObject *py_check_sig = NULL; + PRBool check_sig = 0; + PRTime pr_time = 0; + long required_usages = 0; + SECCertificateUsage returned_usages = 0; + + TraceMethodEnter(self); + + argc = PyTuple_Size(args); + if (argc == n_base_args) { + Py_INCREF(args); + parse_args = args; + } else { + parse_args = PyTuple_GetSlice(args, 0, n_base_args); + } + if (!PyArg_ParseTuple(parse_args, "O!O!lO&:verify", + &CertDBType, &py_certdb, + &PyBool_Type, &py_check_sig, + &required_usages, + PRTimeConvert, &pr_time)) { + Py_DECREF(parse_args); + return NULL; + } + Py_DECREF(parse_args); + + check_sig = PyBoolAsPRBool(py_check_sig); + pin_args = PyTuple_GetSlice(args, n_base_args, argc); + + Py_BEGIN_ALLOW_THREADS + if (CERT_VerifyCertificate(py_certdb->handle, self->cert, check_sig, + required_usages, pr_time, pin_args, + NULL, &returned_usages) != SECSuccess) { + Py_BLOCK_THREADS + Py_DECREF(pin_args); + return set_cert_verify_error(returned_usages, NULL, NULL); + } + Py_END_ALLOW_THREADS + Py_DECREF(pin_args); + + return PyInt_FromLong(returned_usages); +} + +PyDoc_STRVAR(Certificate_verify_with_log_doc, +"verify_with_log(certdb, check_sig, required_usages, time, [user_data1, ...]) -> valid_usages, log\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\ + 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\ + user_dataN : object\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\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 and a `nss.CertVerifyLog`\n\ +object with diagnostic information detailing the reasons for a validation failure.\n\ +\n\ +If required_usages is non-zero, the returned bitmap is only for those\n\ +required usages, otherwise it is for all possible usages.\n\ +\n\ +Hint: You can obtain a printable representation of the usage flags\n\ +via `cert_usage_flags`.\n\ +\n\ +Note: See the `Certificate.verify` documentation for details on how\n\ +the Certificate verification functions handle errors.\n\ +"); + +static PyObject * +Certificate_verify_with_log(Certificate *self, PyObject *args) +{ + Py_ssize_t n_base_args = 4; + Py_ssize_t argc; + PyObject *parse_args = NULL; + PyObject *pin_args = NULL; + CertDB *py_certdb = NULL; + PyObject *py_check_sig = NULL; + PRBool check_sig = 0; + PRTime pr_time = 0; + CertVerifyLog *py_log = NULL; + long required_usages = 0; + SECCertificateUsage returned_usages = 0; + + TraceMethodEnter(self); + + argc = PyTuple_Size(args); + if (argc == n_base_args) { + Py_INCREF(args); + parse_args = args; + } else { + parse_args = PyTuple_GetSlice(args, 0, n_base_args); + } + if (!PyArg_ParseTuple(parse_args, "O!O!lO&:verify_with_log", + &CertDBType, &py_certdb, + &PyBool_Type, &py_check_sig, + &required_usages, + PRTimeConvert, &pr_time)) { + Py_DECREF(parse_args); + return NULL; + } + Py_DECREF(parse_args); + + check_sig = PyBoolAsPRBool(py_check_sig); + pin_args = PyTuple_GetSlice(args, n_base_args, argc); + + if ((py_log = (CertVerifyLog *)CertVerifyLog_new(&CertVerifyLogType, NULL, NULL)) == NULL) { + Py_DECREF(pin_args); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + if (CERT_VerifyCertificate(py_certdb->handle, self->cert, check_sig, + required_usages, pr_time, pin_args, + &py_log->log, &returned_usages) != SECSuccess) { + Py_BLOCK_THREADS + Py_DECREF(pin_args); + return set_cert_verify_error(returned_usages, (PyObject *)py_log, NULL); + } + Py_END_ALLOW_THREADS + Py_DECREF(pin_args); + + return Py_BuildValue("KN", returned_usages, py_log); +} + PyDoc_STRVAR(Certificate_get_extension_doc, "get_extension(oid) -> `CertificateExtension`\n\ \n\ @@ -8800,6 +9104,86 @@ Certificate_get_extension(Certificate *self, PyObject *args, PyObject *kwds) } +PyDoc_STRVAR(Certificate_get_cert_chain_doc, +"get_cert_chain(time=now, usages=certUsageAnyCA) -> (`Certificate`, ...)\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\ + usages : integer\n\ + a certUsage* enumerated constant\n\ +\n\ +Returns a tuple of `Certificate` objects.\n\ +"); + +static PyObject * +Certificate_get_cert_chain(Certificate *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"time", "usages", NULL}; + PRTime pr_time = 0; + int usages = certUsageAnyCA; + CERTCertList *cert_list = NULL; + PyObject *tuple = NULL; + + TraceMethodEnter(self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&i:get_cert_chain", kwlist, + PRTimeConvert, &pr_time, &usages)) + return NULL; + + if ((cert_list = CERT_GetCertChainFromCert(self->cert, pr_time, usages)) == NULL) { + return set_nspr_error(NULL); + } + + tuple = CERTCertList_to_tuple(cert_list); + CERT_DestroyCertList(cert_list); + return tuple; +} + +static PyObject * +Certificate_summary_format_lines(Certificate *self, int level, PyObject *lines) +{ + PyObject *obj = NULL; + PyObject *obj1 = NULL; + PyObject *obj2 = NULL; + + if ((obj = Certificate_get_subject(self, NULL)) == NULL) { + goto fail; + } + FMT_OBJ_AND_APPEND(lines, _("Subject"), obj, level, fail); + Py_CLEAR(obj); + + if ((obj = Certificate_get_issuer(self, NULL)) == NULL) { + goto fail; + } + FMT_OBJ_AND_APPEND(lines, _("Issuer"), obj, level, fail); + Py_CLEAR(obj); + + if ((obj1 = Certificate_get_valid_not_before_str(self, NULL)) == NULL) { + goto fail; + } + if ((obj2 = Certificate_get_valid_not_after_str(self, NULL)) == NULL) { + goto fail; + } + if ((obj = obj_sprintf("[%s] - [%s]", obj1, obj2)) == NULL) { + goto fail; + } + Py_CLEAR(obj1); + Py_CLEAR(obj2); + FMT_OBJ_AND_APPEND(lines, _("Validity"), obj, level, fail); + Py_CLEAR(obj); + + return lines; + fail: + Py_XDECREF(obj); + Py_XDECREF(obj1); + Py_XDECREF(obj2); + return NULL; +} + static PyObject * Certificate_format_lines(Certificate *self, PyObject *args, PyObject *kwds) { @@ -8998,8 +9382,12 @@ static PyMethodDef Certificate_methods[] = { {"make_ca_nickname", (PyCFunction)Certificate_make_ca_nickname, METH_NOARGS, Certificate_make_ca_nickname_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}, + {"check_valid_times", (PyCFunction)Certificate_check_valid_times, METH_VARARGS|METH_KEYWORDS, Certificate_check_valid_times_doc}, + {"is_ca_cert", (PyCFunction)Certificate_is_ca_cert, METH_VARARGS|METH_KEYWORDS, Certificate_is_ca_cert_doc}, {"verify_now", (PyCFunction)Certificate_verify_now, METH_VARARGS, Certificate_verify_now_doc}, + {"verify", (PyCFunction)Certificate_verify, METH_VARARGS, Certificate_verify_doc}, + {"verify_with_log", (PyCFunction)Certificate_verify_with_log, METH_VARARGS, Certificate_verify_with_log_doc}, + {"get_cert_chain", (PyCFunction)Certificate_get_cert_chain, METH_VARARGS|METH_KEYWORDS, Certificate_get_cert_chain_doc}, {"get_extension", (PyCFunction)Certificate_get_extension, METH_VARARGS|METH_KEYWORDS, Certificate_get_extension_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}, @@ -9138,7 +9526,9 @@ Certificate_new_from_CERTCertificate(CERTCertificate *cert) return NULL; } - self->cert = cert; + if ((self->cert = CERT_DupCertificate(cert)) == NULL) { + return set_nspr_error(NULL); + } TraceObjNewLeave(self); return (PyObject *) self; @@ -12492,6 +12882,29 @@ PK11Slot_generate_key_pair(PK11Slot *self, PyObject *args) return NULL; } +PyDoc_STRVAR(PK11Slot_list_certs_doc, +"list_certs() -> (`Certificate`, ...)\n\ +\n\ +Returns a tuple of `Certificate` objects found in the slot.\n\ +"); + +static PyObject * +PK11Slot_list_certs(PK11Slot *self, PyObject *args) +{ + CERTCertList *cert_list = NULL; + PyObject *tuple = NULL; + + TraceMethodEnter(self); + + if ((cert_list = PK11_ListCertsInSlot(self->slot)) == NULL) { + return set_nspr_error(NULL); + } + + tuple = CERTCertList_to_tuple(cert_list); + CERT_DestroyCertList(cert_list); + return tuple; +} + 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}, @@ -12514,6 +12927,7 @@ static PyMethodDef PK11Slot_methods[] = { {"get_best_key_length", (PyCFunction)PK11Slot_get_best_key_length, METH_VARARGS, PK11Slot_get_best_key_length_doc}, {"key_gen", (PyCFunction)PK11Slot_key_gen, METH_VARARGS, PK11Slot_key_gen_doc}, {"generate_key_pair", (PyCFunction)PK11Slot_generate_key_pair, METH_VARARGS, PK11Slot_generate_key_pair_doc}, + {"list_certs", (PyCFunction)PK11Slot_list_certs, METH_NOARGS, PK11Slot_list_certs_doc}, {NULL, NULL} /* Sentinel */ }; @@ -13346,7 +13760,7 @@ CRLDistributionPt_get_crl_issuer(CRLDistributionPt *self, void *closure) static PyGetSetDef CRLDistributionPt_getseters[] = { {"issuer", (getter)CRLDistributionPt_get_crl_issuer, (setter)NULL, - "returns the CRL Issuer as a GeneralName object if defined, returns None if not defined", NULL}, + "returns the CRL Issuer as a `GeneralName` object if defined, returns None if not defined", NULL}, {NULL} /* Sentinel */ }; @@ -17047,6 +17461,576 @@ static PyTypeObject PKCS12DecoderType = { PKCS12Decoder_new, /* tp_new */ }; + +/* ========================================================================== */ +/* ======================== CertVerifyLogNode Class ========================= */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +CertVerifyLogNode_get_certificate(CertVerifyLogNode *self, void *closure) +{ + TraceMethodEnter(self); + + return Certificate_new_from_CERTCertificate(self->node.cert); +} + +static PyObject * +CertVerifyLogNode_get_error(CertVerifyLogNode *self, void *closure) +{ + TraceMethodEnter(self); + + return PyInt_FromLong(self->node.error); +} + +static PyObject * +CertVerifyLogNode_get_depth(CertVerifyLogNode *self, void *closure) +{ + TraceMethodEnter(self); + + return PyInt_FromLong(self->node.depth); +} + +static +PyGetSetDef CertVerifyLogNode_getseters[] = { + {"certificate", (getter)CertVerifyLogNode_get_certificate, NULL, + "returns the certificate as a `Certificate` object", NULL}, + {"error", (getter)CertVerifyLogNode_get_error, NULL, + "returns the error code as an integer", NULL}, + {"depth", (getter)CertVerifyLogNode_get_depth, NULL, + "returns the chain position as an integer", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef CertVerifyLogNode_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +CertVerifyLogNodeError_format_lines(CertVerifyLogNode *self, int level, PyObject *lines) +{ + RepresentationKind repr_kind = AsEnumName; + PyObject *obj = NULL; + PyObject *py_cert = NULL; + NSPRErrorDesc const *error_desc = NULL; + CERTVerifyLogNode *node = NULL; + + if (!lines) { + goto fail; + } + + node = &self->node; + + if ((error_desc = lookup_nspr_error(node->error)) == NULL) { + if ((obj = PyString_FromFormat(_("Unknown error code %ld (%#lx)"), + node->error, node->error)) == NULL) { + goto fail; + } + } else { + if ((obj = PyString_FromFormat("[%s] %s", + error_desc->name, + error_desc->string)) == NULL) { + goto fail; + } + } + FMT_OBJ_AND_APPEND(lines, _("Error"), obj, level, fail); + Py_CLEAR(obj); + + switch (node->error) { + case SEC_ERROR_INADEQUATE_KEY_USAGE: { + unsigned int flags = (unsigned int)node->arg; + + if ((obj = key_usage_flags(flags, repr_kind)) == NULL) { + goto fail; + } + FMT_OBJ_AND_APPEND(lines, _("Inadequate Key Usage"), obj, level, fail); + Py_CLEAR(obj); + } break; + case SEC_ERROR_INADEQUATE_CERT_TYPE: { + unsigned int flags = (unsigned int)node->arg; + + if ((obj = cert_type_flags(flags, repr_kind)) == NULL) { + goto fail; + } + FMT_OBJ_AND_APPEND(lines, _("Inadequate Cert Type"), obj, level, fail); + Py_CLEAR(obj); + } break; + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_ISSUER: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + if ((py_cert = Certificate_new_from_CERTCertificate(node->cert)) == NULL) { + goto fail; + } + if ((obj = Certificate_get_issuer((Certificate *)py_cert, NULL)) == NULL) { + goto fail; + } + Py_CLEAR(py_cert); + + FMT_OBJ_AND_APPEND(lines, _("Issuer"), obj, level, fail); + Py_CLEAR(obj); + break; + default: + break; + } + + return lines; + fail: + Py_XDECREF(py_cert); + Py_XDECREF(obj); + return NULL; +} + +static PyObject * +CertVerifyLogNode_format_lines(CertVerifyLogNode *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + Certificate *py_cert = NULL; + CERTVerifyLogNode *node = NULL; + + TraceMethodEnter(self); + + node = &self->node; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) { + return NULL; + } + + FMT_LABEL_AND_APPEND(lines, _("Certificate"), level, fail); + + if ((py_cert = (Certificate *)Certificate_new_from_CERTCertificate(node->cert)) == NULL) { + goto fail; + } + + if (Certificate_summary_format_lines(py_cert, level+1, lines) == NULL) { + goto fail; + } + + if ((obj = PyInt_FromLong(node->depth)) == NULL){ + goto fail; + } + FMT_OBJ_AND_APPEND(lines, _("Depth"), obj, level, fail); + Py_CLEAR(obj); + + if (CertVerifyLogNodeError_format_lines(self, level, lines) == NULL) { + goto fail; + } + + return lines; + fail: + Py_XDECREF(py_cert); + Py_XDECREF(obj); + Py_XDECREF(lines); + return NULL; +} + +static PyObject * +CertVerifyLogNode_format(CertVerifyLogNode *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter(self); + + return format_from_lines((format_lines_func)CertVerifyLogNode_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +CertVerifyLogNode_str(CertVerifyLogNode *self) +{ + PyObject *py_formatted_result = NULL; + + TraceMethodEnter(self); + + py_formatted_result = CertVerifyLogNode_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + + +static PyMethodDef CertVerifyLogNode_methods[] = { + {"format_lines", (PyCFunction)CertVerifyLogNode_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)CertVerifyLogNode_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Class Construction =========================== */ + +static PyObject * +CertVerifyLogNode_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CertVerifyLogNode *self; + + TraceObjNewEnter(type); + + if ((self = (CertVerifyLogNode *)type->tp_alloc(type, 0)) == NULL) { + return NULL; + } + + memset(&self->node, 0, sizeof(self->node)); + + TraceObjNewLeave(self); + return (PyObject *)self; +} + +static void +CertVerifyLogNode_dealloc(CertVerifyLogNode* self) +{ + TraceMethodEnter(self); + + if (self->node.cert) { + CERT_DestroyCertificate(self->node.cert); + } + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(CertVerifyLogNode_doc, +"CertVerifyLogNode()\n\ +\n\ +An object detailing specific diagnostic information concerning\n\ +a single failure during certification validation.\n\ +These are collected in a `CertVerifyLog` object.\n\ +"); + +static PyTypeObject CertVerifyLogNodeType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.CertVerifyLogNode", /* tp_name */ + sizeof(CertVerifyLogNode), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)CertVerifyLogNode_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)CertVerifyLogNode_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + CertVerifyLogNode_doc, /* tp_doc */ + (traverseproc)0, /* tp_traverse */ + (inquiry)0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CertVerifyLogNode_methods, /* tp_methods */ + CertVerifyLogNode_members, /* tp_members */ + CertVerifyLogNode_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + CertVerifyLogNode_new, /* tp_new */ +}; + +static PyObject * +CertVerifyLogNode_new_from_CERTVerifyLogNode(CERTVerifyLogNode *node) +{ + CertVerifyLogNode *self = NULL; + + TraceObjNewEnter(NULL); + + if ((self = (CertVerifyLogNode *) CertVerifyLogNodeType.tp_new(&CertVerifyLogNodeType, NULL, NULL)) == NULL) { + return NULL; + } + + self->node.cert = CERT_DupCertificate(node->cert); + self->node.error = node->error; + self->node.depth = node->depth; + self->node.arg = node->arg; + self->node.next = NULL; + self->node.prev = NULL; + + TraceObjNewLeave(self); + + return (PyObject *) self; +} +/* ========================================================================== */ +/* ========================== CertVerifyLog Class =========================== */ +/* ========================================================================== */ + +/* ============================ Attribute Access ============================ */ + +static PyObject * +CertVerifyLog_get_count(CertVerifyLog *self, void *closure) +{ + TraceMethodEnter(self); + + return PyInt_FromLong(self->log.count); +} + +static +PyGetSetDef CertVerifyLog_getseters[] = { + {"count", (getter)CertVerifyLog_get_count, NULL, + "number of validation errors", NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef CertVerifyLog_members[] = { + {NULL} /* Sentinel */ +}; + +/* ============================== Class Methods ============================= */ + +static PyObject * +CertVerifyLog_format_lines(CertVerifyLog *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"level", NULL}; + int level = 0; + PyObject *lines = NULL; + PyObject *obj = NULL; + Py_ssize_t i, n_items; + unsigned int depth = ~0; + CertVerifyLogNode *py_node = NULL; + Certificate *py_cert = NULL; + + TraceMethodEnter(self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:format_lines", kwlist, &level)) + return NULL; + + if ((lines = PyList_New(0)) == NULL) { + return NULL; + } + + if ((obj = PyInt_FromLong(self->log.count)) == NULL) { + goto fail; + } + FMT_OBJ_AND_APPEND(lines, _("Validation Errors"), obj, level, fail); + Py_CLEAR(obj); + + + n_items = CertVerifyLog_length(self); + + for (i = 0; i < n_items; i++) { + CERTVerifyLogNode *node = NULL; + + py_node = (CertVerifyLogNode *)CertVerifyLog_item(self, i); + node = &py_node->node; + + if (depth != node->depth) { + depth = node->depth; + + if ((obj = PyString_FromFormat(_("Certificate at chain depth %u"), node->depth)) == NULL) { + goto fail; + } + FMT_LABEL_AND_APPEND(lines, PyString_AsString(obj), level, fail); + Py_CLEAR(obj); + + if ((py_cert = (Certificate *)Certificate_new_from_CERTCertificate(node->cert)) == NULL) { + goto fail; + } + + if (Certificate_summary_format_lines(py_cert, level+1, lines) == NULL) { + goto fail; + } + + Py_CLEAR(py_cert); + + /* Add blank line between cert and errors */ + FMT_LABEL_AND_APPEND(lines, NULL, level, fail); + } + + if ((obj = PyString_FromFormat(_("Validation Error #%u"), i+1)) == NULL) { + goto fail; + } + FMT_LABEL_AND_APPEND(lines, PyString_AsString(obj), level+1, fail); + Py_CLEAR(obj); + + if (CertVerifyLogNodeError_format_lines(py_node, level+2, lines) == NULL) { + goto fail; + } + + Py_CLEAR(py_node); + + //if (i < n_items-1) { /* blank separator line */ + // FMT_LABEL_AND_APPEND(lines, NULL, level, fail); + //} + + } + + return lines; + fail: + Py_XDECREF(py_node); + Py_XDECREF(py_cert); + Py_XDECREF(obj); + Py_XDECREF(lines); + return NULL; +} + +static PyObject * +CertVerifyLog_format(CertVerifyLog *self, PyObject *args, PyObject *kwds) +{ + TraceMethodEnter(self); + + return format_from_lines((format_lines_func)CertVerifyLog_format_lines, (PyObject *)self, args, kwds); +} + +static PyObject * +CertVerifyLog_str(CertVerifyLog *self) +{ + PyObject *py_formatted_result = NULL; + + TraceMethodEnter(self); + + py_formatted_result = CertVerifyLog_format(self, empty_tuple, NULL); + return py_formatted_result; + +} + +static PyMethodDef CertVerifyLog_methods[] = { + {"format_lines", (PyCFunction)CertVerifyLog_format_lines, METH_VARARGS|METH_KEYWORDS, generic_format_lines_doc}, + {"format", (PyCFunction)CertVerifyLog_format, METH_VARARGS|METH_KEYWORDS, generic_format_doc}, + {NULL, NULL} /* Sentinel */ +}; + +/* =========================== Sequence Protocol ============================ */ +static Py_ssize_t +CertVerifyLog_length(CertVerifyLog *self) +{ + return self->log.count; +} + +static PyObject * +CertVerifyLog_item(CertVerifyLog *self, register Py_ssize_t i) +{ + CERTVerifyLogNode *node = NULL; + Py_ssize_t index; + + for (node = self->log.head, index = 0; + node && index <= i; + node = node->next, index++) { + if (i == index) { + return CertVerifyLogNode_new_from_CERTVerifyLogNode(node); + } + } + + PyErr_SetString(PyExc_IndexError, "CertVerifyLog index out of range"); + return NULL; +} + + +/* =========================== Class Construction =========================== */ + +static PyObject * +CertVerifyLog_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CertVerifyLog *self; + + TraceObjNewEnter(type); + + if ((self = (CertVerifyLog *)type->tp_alloc(type, 0)) == NULL) { + return NULL; + } + + if ((self->log.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE)) == NULL) { + type->tp_free(self); + return set_nspr_error(NULL); + } + + self->log.count = 0; + self->log.head = NULL; + self->log.tail = NULL; + + TraceObjNewLeave(self); + return (PyObject *)self; +} + +static void +CertVerifyLog_dealloc(CertVerifyLog* self) +{ + CERTVerifyLogNode *node = NULL; + + TraceMethodEnter(self); + + for (node = self->log.head; node; node = node->next) { + if (node->cert) { + CERT_DestroyCertificate(node->cert); + } + } + PORT_FreeArena(self->log.arena, PR_FALSE); + + self->ob_type->tp_free((PyObject*)self); +} + +PyDoc_STRVAR(CertVerifyLog_doc, +"CertVerifyLog()\n\ +\n\ +An object which collects diagnostic information during\n\ +certification validation.\n\ +"); + +static PySequenceMethods CertVerifyLog_as_sequence = { + (lenfunc)CertVerifyLog_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)CertVerifyLog_item, /* 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 CertVerifyLogType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "nss.nss.CertVerifyLog", /* tp_name */ + sizeof(CertVerifyLog), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)CertVerifyLog_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &CertVerifyLog_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)CertVerifyLog_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + CertVerifyLog_doc, /* tp_doc */ + (traverseproc)0, /* tp_traverse */ + (inquiry)0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CertVerifyLog_methods, /* tp_methods */ + CertVerifyLog_members, /* tp_members */ + CertVerifyLog_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + CertVerifyLog_new, /* tp_new */ +}; /* ========================== PK11 Methods =========================== */ static char * @@ -17194,6 +18178,179 @@ pk11_set_password_callback(PyObject *self, PyObject *args) Py_RETURN_NONE; } +PyDoc_STRVAR(pk11_list_certs_doc, +"list_certs(type, [user_data1, ...]) -> (`Certificate`, ...)\n\ +\n\ +:Parameters:\n\ + type : int\n\ + PK11CertList* enumerated constant.\n\ + user_dataN : object ...\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\n\ +\n\ +Given the type of certificates to list return a tuple of `Certificate`\n\ +objects matching that type.\n\ +"); + +static PyObject * +pk11_list_certs(PyObject *self, PyObject *args) +{ + Py_ssize_t n_base_args = 1; + Py_ssize_t argc; + PyObject *parse_args = NULL; + PyObject *pin_args = NULL; + int type = PK11CertListAll; + CERTCertList *cert_list = NULL; + PyObject *tuple = NULL; + + TraceMethodEnter(self); + + argc = PyTuple_Size(args); + if (argc == n_base_args) { + Py_INCREF(args); + parse_args = args; + } else { + parse_args = PyTuple_GetSlice(args, 0, n_base_args); + } + if (!PyArg_ParseTuple(parse_args, "i:list_certs", &type)) { + Py_DECREF(parse_args); + return NULL; + } + Py_DECREF(parse_args); + + pin_args = PyTuple_GetSlice(args, n_base_args, argc); + + Py_BEGIN_ALLOW_THREADS + if ((cert_list = PK11_ListCerts(type, pin_args)) == NULL) { + Py_BLOCK_THREADS + Py_DECREF(pin_args); + return set_nspr_error(NULL); + } + Py_END_ALLOW_THREADS + + Py_DECREF(pin_args); + + tuple = CERTCertList_to_tuple(cert_list); + CERT_DestroyCertList(cert_list); + return tuple; +} + +PyDoc_STRVAR(pk11_find_certs_from_email_addr_doc, +"find_certs_from_email_addr(email, [user_data1, ...]) -> (`Certificate`, ...)\n\ +\n\ +:Parameters:\n\ + email : string\n\ + email address.\n\ + user_dataN : object ...\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\n\ +\n\ +Given an email address return a tuple of `Certificate`\n\ +objects containing that address.\n\ +"); + +static PyObject * +pk11_find_certs_from_email_addr(PyObject *self, PyObject *args) +{ + Py_ssize_t n_base_args = 1; + Py_ssize_t argc; + PyObject *parse_args = NULL; + PyObject *pin_args = NULL; + char *email_addr = NULL; + CERTCertList *cert_list = NULL; + PyObject *tuple = NULL; + + TraceMethodEnter(self); + + argc = PyTuple_Size(args); + if (argc == n_base_args) { + Py_INCREF(args); + parse_args = args; + } else { + parse_args = PyTuple_GetSlice(args, 0, n_base_args); + } + if (!PyArg_ParseTuple(parse_args, "s:find_certs_from_email_addr", + &email_addr)) { + Py_DECREF(parse_args); + return NULL; + } + Py_DECREF(parse_args); + + pin_args = PyTuple_GetSlice(args, n_base_args, argc); + + Py_BEGIN_ALLOW_THREADS + if ((cert_list = PK11_FindCertsFromEmailAddress(email_addr, pin_args)) == NULL) { + Py_BLOCK_THREADS + Py_DECREF(pin_args); + return set_nspr_error(NULL); + } + Py_END_ALLOW_THREADS + + Py_DECREF(pin_args); + + tuple = CERTCertList_to_tuple(cert_list); + CERT_DestroyCertList(cert_list); + return tuple; +} + +PyDoc_STRVAR(pk11_find_certs_from_nickname_doc, +"find_certs_from_nickname(email, [user_data1, ...]) -> (`Certificate`, ...)\n\ +\n\ +:Parameters:\n\ + nickname : string\n\ + certificate nickname.\n\ + user_dataN : object ...\n\ + zero or more caller supplied parameters which will\n\ + be passed to the password callback function\n\ +\n\ +Given a certificate nickname return a tuple of `Certificate`\n\ +objects matching that nickname.\n\ +"); + +static PyObject * +pk11_find_certs_from_nickname(PyObject *self, PyObject *args) +{ + Py_ssize_t n_base_args = 1; + Py_ssize_t argc; + PyObject *parse_args = NULL; + PyObject *pin_args = NULL; + char *nickname = NULL; + CERTCertList *cert_list = NULL; + PyObject *tuple = NULL; + + TraceMethodEnter(self); + + argc = PyTuple_Size(args); + if (argc == n_base_args) { + Py_INCREF(args); + parse_args = args; + } else { + parse_args = PyTuple_GetSlice(args, 0, n_base_args); + } + if (!PyArg_ParseTuple(parse_args, "s:find_certs_from_nickname", + &nickname)) { + Py_DECREF(parse_args); + return NULL; + } + Py_DECREF(parse_args); + + pin_args = PyTuple_GetSlice(args, n_base_args, argc); + + Py_BEGIN_ALLOW_THREADS + if ((cert_list = PK11_FindCertsFromNickname(nickname, pin_args)) == NULL) { + Py_BLOCK_THREADS + Py_DECREF(pin_args); + return set_nspr_error(NULL); + } + Py_END_ALLOW_THREADS + + Py_DECREF(pin_args); + + tuple = CERTCertList_to_tuple(cert_list); + CERT_DestroyCertList(cert_list); + return tuple; +} + PyDoc_STRVAR(pk11_find_cert_from_nickname_doc, "find_cert_from_nickname(nickname, [user_data1, ...]) -> Certificate\n\ \n\ @@ -19266,6 +20423,51 @@ cert_x509_key_usage(PyObject *self, PyObject *args, PyObject *kwds) return result; } +PyDoc_STRVAR(cert_x509_cert_type_doc, +"x509_cert_type(bitstr, repr_kind=AsEnumDescription) -> (str, ...)\n\ +\n\ +:Parameters:\n\ + bitstr : SecItem object\n\ + A SecItem containing a DER encoded bit string.\n\ + repr_kind : RepresentationKind constant\n\ + Specifies what the contents of the returned tuple will be.\n\ + May be one of:\n\ +\n\ + AsEnum\n\ + The enumerated constant.\n\ + (e.g. nss.NS_CERT_TYPE_SSL_SERVER)\n\ + AsEnumDescription\n\ + A friendly human readable description of the enumerated constant as a string.\n\ + (e.g. \"SSL Server\")\n\ + AsIndex\n\ + The bit position within the bit string.\n\ +\n\ +Return a tuple of string name for each enabled bit in the key\n\ +usage bit string.\n\ +"); + +static PyObject * +cert_x509_cert_type(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"bitstr", "repr_kind", NULL}; + PyObject *result; + SecItem *py_sec_item; + SECItem bitstr_item; + int repr_kind = AsEnumDescription; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|i:x509_cert_type", kwlist, + &SecItemType, &py_sec_item, &repr_kind)) + return NULL; + + if (der_bitstring_to_nss_bitstring(&bitstr_item, &py_sec_item->item) != SECSuccess) { + return set_nspr_error(NULL); + } + + result = cert_type_bitstr_to_tuple(&bitstr_item, repr_kind); + + return result; +} + PyDoc_STRVAR(cert_x509_ext_key_usage_doc, "x509_ext_key_usage(sec_item, repr_kind=AsString) -> (obj, ...)\n\ \n\ @@ -19684,11 +20886,21 @@ cert_general_name_type_from_name(PyObject *self, PyObject *args) } PyDoc_STRVAR(cert_cert_usage_flags_doc, -"cert_usage_flags(flags) -> ['flag_name', ...]\n\ +"cert_usage_flags(flags, repr_kind=AsEnumDescription) -> ['flag_name', ...]\n\ \n\ :Parameters:\n\ flags : int\n\ certificateUsage* bit flags\n\ + repr_kind : RepresentationKind constant\n\ + Specifies what the contents of the returned list will be.\n\ + May be one of:\n\ +\n\ + AsEnum\n\ + The enumerated constant as an integer value.\n\ + AsEnumName\n\ + The name of the enumerated constant as a string.\n\ + AsEnumDescription\n\ + A friendly human readable description of the enumerated constant as a string.\n\ \n\ Given an integer with certificateUsage*\n\ (e.g. nss.certificateUsageSSLServer) bit flags return a sorted\n\ @@ -19696,25 +20908,115 @@ list of their string names.\n\ "); static PyObject * -cert_cert_usage_flags(PyObject *self, PyObject *args) +cert_cert_usage_flags(PyObject *self, PyObject *args, PyObject *kwds) { + static char *kwlist[] = {"flags", "repr_kind", NULL}; int flags = 0; + RepresentationKind repr_kind = AsEnumDescription; TraceMethodEnter(self); - if (!PyArg_ParseTuple(args, "i:cert_usage_flags", - &flags)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|i:cert_usage_flags", kwlist, + &flags, &repr_kind)) return NULL; - return cert_usage_flags(flags); + return cert_usage_flags(flags, repr_kind); +} + +PyDoc_STRVAR(cert_key_usage_flags_doc, +"key_usage_flags(flags, repr_kind=AsEnumName) -> ['flag_name', ...]\n\ +\n\ +:Parameters:\n\ + flags : int\n\ + KU_* bit flags\n\ + repr_kind : RepresentationKind constant\n\ + Specifies what the contents of the returned list will be.\n\ + May be one of:\n\ +\n\ + AsEnum\n\ + The enumerated constant as an integer value.\n\ + AsEnumName\n\ + The name of the enumerated constant as a string.\n\ + AsEnumDescription\n\ + A friendly human readable description of the enumerated constant as a string.\n\ +\n\ +Given an integer with KU_*\n\ +(e.g. nss.KU_DIGITAL_SIGNATURE) bit flags return a sorted\n\ +list of their string names.\n\ +"); + +static PyObject * +cert_key_usage_flags(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"flags", "repr_kind", NULL}; + int flags = 0; + RepresentationKind repr_kind = AsEnumName; + + TraceMethodEnter(self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|i:key_usage_flags", kwlist, + &flags, &repr_kind)) + return NULL; + + return key_usage_flags(flags, repr_kind); +} + +PyDoc_STRVAR(cert_cert_type_flags_doc, +"cert_type_flags(flags, repr_kind=AsEnumName) -> ['flag_name', ...]\n\ +\n\ +:Parameters:\n\ + flags : int\n\ + KU_* bit flags\n\ + repr_kind : RepresentationKind constant\n\ + Specifies what the contents of the returned list will be.\n\ + May be one of:\n\ +\n\ + AsEnum\n\ + The enumerated constant as an integer value.\n\ + AsEnumName\n\ + The name of the enumerated constant as a string.\n\ + AsEnumDescription\n\ + A friendly human readable description of the enumerated constant as a string.\n\ +\n\ +\n\ +Given an integer with NS_CERT_TYPE_*\n\ +(e.g. nss.NS_CERT_TYPE_SSL_SERVER) bit flags return a sorted\n\ +list of their string names.\n\ +"); + +static PyObject * +cert_cert_type_flags(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"flags", "repr_kind", NULL}; + int flags = 0; + RepresentationKind repr_kind = AsEnumName; + + TraceMethodEnter(self); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|i:cert_type_flags", kwlist, + &flags, &repr_kind)) + return NULL; + + return cert_type_flags(flags, repr_kind); } PyDoc_STRVAR(nss_nss_init_flags_doc, -"nss_init_flags(flags) -> ['flag_name', ...]\n\ +"nss_init_flags(flags, repr_kind=AsEnumName) -> ['flag_name', ...]\n\ \n\ :Parameters:\n\ flags : int\n\ NSS_INIT* bit flags\n\ + repr_kind : RepresentationKind constant\n\ + Specifies what the contents of the returned list will be.\n\ + May be one of:\n\ +\n\ + AsEnum\n\ + The enumerated constant as an integer value.\n\ + AsEnumName\n\ + The name of the enumerated constant as a string.\n\ + AsEnumDescription\n\ + A friendly human readable description of the enumerated constant as a string.\n\ +\n\ \n\ Given an integer with NSS_INIT*\n\ (e.g. nss.NSS_INIT_READONLY) bit flags return a sorted\n\ @@ -19722,17 +21024,19 @@ list of their string names.\n\ "); static PyObject * -nss_nss_init_flags(PyObject *self, PyObject *args) +nss_nss_init_flags(PyObject *self, PyObject *args, PyObject *kwds) { + static char *kwlist[] = {"flags", "repr_kind", NULL}; int flags = 0; + RepresentationKind repr_kind = AsEnumName; TraceMethodEnter(self); - if (!PyArg_ParseTuple(args, "i:nss_init_flags", - &flags)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:nss_init_flags", kwlist, + &flags, &repr_kind)) return NULL; - return nss_init_flags(flags); + return nss_init_flags(flags, repr_kind); } PyDoc_STRVAR(pkcs12_enable_cipher_doc, @@ -20176,6 +21480,68 @@ nss_fingerprint_format_lines(PyObject *self, PyObject *args, PyObject *kwds) return fingerprint_format_lines(der_item, level); } +PyDoc_STRVAR(nss_get_use_pkix_for_validation_doc, +"get_use_pkix_for_validation() -> flag\n\ +\n\ +Returns the current value of the flag used to enable or disable the\n\ +use of PKIX for certificate validation. See also:\n\ +`set_use_pkix_for_validation`.\n\ +"); + +static PyObject * +nss_get_use_pkix_for_validation(PyObject *self, PyObject *args) +{ + PRBool flag; + + TraceMethodEnter(self); + + flag = CERT_GetUsePKIXForValidation(); + + if (flag) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + +PyDoc_STRVAR(nss_set_use_pkix_for_validation_doc, +"set_use_pkix_for_validation(flag) -> prev_flag\n\ +\n\ +:Parameters:\n\ + flag : boolean\n\ + Boolean flag, True to enable PKIX validation,\n\ + False to disable PKIX validation.\n\ +\n\ +Sets the flag to enable or disable the use of PKIX for certificate\n\ +validation. Returns the previous value of the flag.\n\ +See also: `get_use_pkix_for_validation`.\n\ +"); + +static PyObject * +nss_set_use_pkix_for_validation(PyObject *self, PyObject *args) +{ + int flag; + PRBool prev_flag; + + TraceMethodEnter(self); + + if (!PyArg_ParseTuple(args, "i:set_use_pkix_for_validation", + &flag)) + return NULL; + + prev_flag = CERT_GetUsePKIXForValidation(); + + if (CERT_SetUsePKIXForValidation(flag ? PR_TRUE : PR_FALSE) != SECSuccess) { + return set_nspr_error(NULL); + } + + if (prev_flag) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + /* List of functions exported by this module. */ static PyMethodDef module_methods[] = { @@ -20189,6 +21555,9 @@ module_methods[] = { {"nss_shutdown_context", (PyCFunction)nss_nss_shutdown_context, METH_VARARGS, nss_nss_shutdown_context_doc}, {"dump_certificate_cache_info", (PyCFunction)nss_dump_certificate_cache_info, METH_NOARGS, nss_dump_certificate_cache_info_doc}, {"set_password_callback", (PyCFunction)pk11_set_password_callback, METH_VARARGS, pk11_set_password_callback_doc}, + {"list_certs", (PyCFunction)pk11_list_certs, METH_VARARGS, pk11_list_certs_doc}, + {"find_certs_from_email_addr", (PyCFunction)pk11_find_certs_from_email_addr, METH_VARARGS, pk11_find_certs_from_email_addr_doc}, + {"find_certs_from_nickname", (PyCFunction)pk11_find_certs_from_nickname, METH_VARARGS, pk11_find_certs_from_nickname_doc}, {"find_cert_from_nickname", (PyCFunction)pk11_find_cert_from_nickname, METH_VARARGS, pk11_find_cert_from_nickname_doc}, {"find_key_by_any_cert", (PyCFunction)pk11_find_key_by_any_cert, METH_VARARGS, pk11_find_key_by_any_cert_doc}, {"generate_random", (PyCFunction)pk11_generate_random, METH_VARARGS, pk11_generate_random_doc}, @@ -20239,14 +21608,16 @@ module_methods[] = { {"need_pw_init", (PyCFunction)pk11_pk11_need_pw_init, METH_NOARGS, pk11_pk11_need_pw_init_doc}, {"token_exists", (PyCFunction)pk11_pk11_token_exists, METH_NOARGS, pk11_pk11_token_exists_doc}, {"is_fips", (PyCFunction)pk11_pk11_is_fips, METH_NOARGS, pk11_pk11_is_fips_doc}, - /* jrdpk11 */ {"decode_der_crl", (PyCFunction)cert_decode_der_crl, METH_VARARGS|METH_KEYWORDS, cert_decode_der_crl_doc}, {"read_der_from_file", (PyCFunction)cert_read_der_from_file, METH_VARARGS|METH_KEYWORDS, cert_read_der_from_file_doc}, {"x509_key_usage", (PyCFunction)cert_x509_key_usage, METH_VARARGS|METH_KEYWORDS, cert_x509_key_usage_doc}, + {"x509_cert_type", (PyCFunction)cert_x509_cert_type, METH_VARARGS|METH_KEYWORDS, cert_x509_cert_type_doc}, {"x509_ext_key_usage", (PyCFunction)cert_x509_ext_key_usage, METH_VARARGS|METH_KEYWORDS, cert_x509_ext_key_usage_doc}, {"x509_alt_name", (PyCFunction)cert_x509_alt_name, METH_VARARGS|METH_KEYWORDS, cert_x509_alt_name_doc}, - {"cert_usage_flags", (PyCFunction)cert_cert_usage_flags, METH_VARARGS, cert_cert_usage_flags_doc}, - {"nss_init_flags", (PyCFunction)nss_nss_init_flags, METH_VARARGS, nss_nss_init_flags_doc}, + {"cert_usage_flags", (PyCFunction)cert_cert_usage_flags, METH_VARARGS|METH_KEYWORDS, cert_cert_usage_flags_doc}, + {"key_usage_flags", (PyCFunction)cert_key_usage_flags, METH_VARARGS|METH_KEYWORDS, cert_key_usage_flags_doc}, + {"cert_type_flags", (PyCFunction)cert_cert_type_flags, METH_VARARGS|METH_KEYWORDS, cert_cert_type_flags_doc}, + {"nss_init_flags", (PyCFunction)nss_nss_init_flags, METH_VARARGS|METH_KEYWORDS, nss_nss_init_flags_doc}, {"pkcs12_enable_cipher", (PyCFunction)pkcs12_enable_cipher, METH_VARARGS, pkcs12_enable_cipher_doc}, {"pkcs12_enable_all_ciphers", (PyCFunction)pkcs12_enable_all_ciphers, METH_NOARGS, pkcs12_enable_all_ciphers_doc}, {"pkcs12_set_preferred_cipher", (PyCFunction)pkcs12_set_preferred_cipher, METH_VARARGS, pkcs12_set_preferred_cipher_doc}, @@ -20256,6 +21627,8 @@ module_methods[] = { {"pkcs12_set_nickname_collision_callback", (PyCFunction)PKCS12_pkcs12_set_nickname_collision_callback, METH_VARARGS, PKCS12_pkcs12_set_nickname_collision_callback_doc}, {"pkcs12_export", (PyCFunction)pkcs12_export, METH_VARARGS|METH_KEYWORDS, pkcs12_export_doc}, {"fingerprint_format_lines", (PyCFunction)nss_fingerprint_format_lines, METH_VARARGS|METH_KEYWORDS, nss_fingerprint_format_lines_doc}, + {"get_use_pkix_for_validation", (PyCFunction)nss_get_use_pkix_for_validation, METH_NOARGS, nss_get_use_pkix_for_validation_doc}, + {"set_use_pkix_for_validation", (PyCFunction)nss_set_use_pkix_for_validation, METH_VARARGS, nss_set_use_pkix_for_validation_doc}, {NULL, NULL} /* Sentinel */ }; @@ -20298,7 +21671,6 @@ initnss(void) if ((empty_tuple = PyTuple_New(0)) == NULL) { return; } - Py_INCREF(empty_tuple); TYPE_READY(SecItemType); @@ -20331,6 +21703,8 @@ initnss(void) TYPE_READY(InitContextType); TYPE_READY(PKCS12DecodeItemType); TYPE_READY(PKCS12DecoderType); + TYPE_READY(CertVerifyLogNodeType); + TYPE_READY(CertVerifyLogType); /* Export C API */ if (PyModule_AddObject(m, "_C_API", PyCObject_FromVoidPtr((void *)&nspr_nss_c_api, NULL)) != 0) { @@ -20354,6 +21728,26 @@ initnss(void) AddIntConstant(generalName); AddIntConstant(relativeDistinguishedName); + AddIntConstant(PK11CertListUnique); + AddIntConstant(PK11CertListUser); + AddIntConstant(PK11CertListRootUnique); + AddIntConstant(PK11CertListCA); + AddIntConstant(PK11CertListCAUnique); + AddIntConstant(PK11CertListUserUnique); + AddIntConstant(PK11CertListAll); + + AddIntConstant(certUsageSSLClient); + AddIntConstant(certUsageSSLServer); + AddIntConstant(certUsageSSLServerWithStepUp); + AddIntConstant(certUsageSSLCA); + AddIntConstant(certUsageEmailSigner); + AddIntConstant(certUsageEmailRecipient); + AddIntConstant(certUsageObjectSigner); + AddIntConstant(certUsageUserCertImport); + AddIntConstant(certUsageVerifyCA); + AddIntConstant(certUsageProtectedObjectSigner); + AddIntConstant(certUsageStatusResponder); + AddIntConstant(certUsageAnyCA); AddIntConstant(certificateUsageCheckAllUsages); AddIntConstant(certificateUsageSSLClient); @@ -20417,6 +21811,18 @@ initnss(void) AddIntConstant(secCertTimeExpired); AddIntConstant(secCertTimeNotValidYet); + AddIntConstant(KU_DIGITAL_SIGNATURE); + AddIntConstant(KU_NON_REPUDIATION); + AddIntConstant(KU_KEY_ENCIPHERMENT); + AddIntConstant(KU_DATA_ENCIPHERMENT); + AddIntConstant(KU_KEY_AGREEMENT); + AddIntConstant(KU_KEY_CERT_SIGN); + AddIntConstant(KU_CRL_SIGN); + AddIntConstant(KU_ENCIPHER_ONLY); + AddIntConstant(KU_ALL); + AddIntConstant(KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION); + AddIntConstant(KU_KEY_AGREEMENT_OR_ENCIPHERMENT); + AddIntConstant(KU_NS_GOVT_APPROVED); /*************************************************************************** * CRL Reason diff --git a/mozilla/security/python/nss/src/py_nss.h b/mozilla/security/python/nss/src/py_nss.h index 23f70c1db7f..11bab4dce42 100644 --- a/mozilla/security/python/nss/src/py_nss.h +++ b/mozilla/security/python/nss/src/py_nss.h @@ -355,6 +355,24 @@ typedef struct { PyObject *py_decode_items; /* tuple */ } PKCS12Decoder; +/* ========================================================================== */ +/* ========================== CertVerifyLogNode Class ======================= */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + CERTVerifyLogNode node; +} CertVerifyLogNode; + +/* ========================================================================== */ +/* ============================ CertVerifyLog Class ========================= */ +/* ========================================================================== */ + +typedef struct { + PyObject_HEAD + CERTVerifyLog log; +} CertVerifyLog; + /* ========================================================================== */ typedef struct {