Add cert validation support & internal clean-up, see Changelog
Prepare for 0.14 release git-svn-id: svn://10.0.0.236/trunk@264395 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1,3 +1,130 @@
|
||||
2012-10-24 John Dennis <jdennis@redhat.com> 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 <jdennis@redhat.com> 0.13
|
||||
* Fix NSS SECITEM_CompareItem bug via workaround.
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
278
mozilla/security/python/nss/doc/examples/verify_cert.py
Executable file
278
mozilla/security/python/nss/doc/examples/verify_cert.py
Executable file
@@ -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())
|
||||
|
||||
|
||||
@@ -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 = '',
|
||||
|
||||
@@ -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" */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -312,5 +312,5 @@ FAQ
|
||||
To be added
|
||||
|
||||
"""
|
||||
__version__ = '0.13'
|
||||
__version__ = '0.14.0alpha'
|
||||
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 <stdbool.h>
|
||||
|
||||
/* 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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user