root/tags/releases/twisted-8.1.0/twisted/internet/_sslverify.py

Revision 18499, 32.9 KB (checked in by exarkun, 4 years ago)

Apply patch from ssl.CO docstring ticket

Author: exarkun
Reviewer: jml
Fixes #2014

Remove documentation implying CertificateOptions is server-only.

Line 
1# -*- test-case-name: twisted.test.test_sslverify -*-
2# Copyright 2005 Divmod, Inc.  See LICENSE file for details
3
4import itertools, md5
5from OpenSSL import SSL, crypto
6
7from twisted.python import reflect, util
8from twisted.internet.defer import Deferred
9from twisted.internet.error import VerifyError, CertificateError
10
11# Private - shared between all OpenSSLCertificateOptions, counts up to provide
12# a unique session id for each context
13_sessionCounter = itertools.count().next
14
15class _SSLApplicationData(object):
16    def __init__(self):
17        self.problems = []
18
19class OpenSSLVerifyError(VerifyError):
20
21    _errorCodes = {0: ('X509_V_OK',
22                       'ok',
23                       'the operation was successful. >'),
24
25                   2: ('X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT',
26                       'unable to get issuer certificate',
27                       "The issuer certificate could not be found.  This "
28                       "occurs if the issuer certificate of an untrusted "
29                       "certificate cannot be found."),
30
31                   3: ('X509_V_ERR_UNABLE_TO_GET_CRL',
32                       'unable to get certificate CRL',
33                       "The CRL of a certificate could not be found. "
34                       "Unused."),
35
36                   4: ('X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE',
37                       "unable to decrypt certificate's signature",
38                       "The certificate signature could not be decrypted.  "
39                       "This means that the actual signature value could not "
40                       "be determined rather than it not matching the "
41                       "expected value, this is only meaningful for RSA "
42                       "keys."),
43
44                   5: ('X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE',
45                       "unable to decrypt CRL's signature",
46                       "The CRL signature could not be decrypted.  This "
47                       "means that the actual signature value could not be "
48                       "determined rather than it not matching the expected "
49                       "value. Unused."),
50
51                   6: ('X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY',
52                       'unable to decode issuer',
53                       "Public key the public key in the certificate "
54                       "SubjectPublicKeyInfo could not be read."),
55
56                   7: ('X509_V_ERR_CERT_SIGNATURE_FAILURE',
57                       'certificate signature failure',
58                       'The signature of the certificate is invalid.'),
59
60                   8: ('X509_V_ERR_CRL_SIGNATURE_FAILURE',
61                       'CRL signature failure',
62                       'The signature of the certificate is invalid. Unused.'),
63
64                   9: ('X509_V_ERR_CERT_NOT_YET_VALID',
65                       'certificate is not yet valid',
66                       "The certificate is not yet valid.  The notBefore "
67                       "date is after the current time."),
68
69                   10: ('X509_V_ERR_CERT_HAS_EXPIRED',
70                        'certificate has expired',
71                        "The certificate has expired.  The notAfter date "
72                        "is before the current time."),
73
74                   11: ('X509_V_ERR_CRL_NOT_YET_VALID',
75                        'CRL is not yet valid',
76                        'The CRL is not yet valid. Unused.'),
77
78                   12: ('X509_V_ERR_CRL_HAS_EXPIRED',
79                        'CRL has expired',
80                        'The CRL has expired. Unused.'),
81
82                   13: ('X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD',
83                        "format error in certificate's notBefore field",
84                        "The certificate's notBefore field contains an "
85                        "invalid time."),
86
87                   14: ('X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD',
88                        "format error in certificate's notAfter field.",
89                        "The certificate's notAfter field contains an "
90                        "invalid time."),
91
92                   15: ('X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD',
93                        "format error in CRL's lastUpdate field",
94                        "The CRL lastUpdate field contains an invalid "
95                        "time. Unused."),
96
97                   16: ('X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD',
98                        "format error in CRL's nextUpdate field",
99                        "The CRL nextUpdate field contains an invalid "
100                        "time. Unused."),
101
102                   17: ('X509_V_ERR_OUT_OF_MEM',
103                        'out of memory',
104                        'An error occurred trying to allocate memory. '
105                        'This should never happen.'),
106
107                   18: ('X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT',
108                        'self signed certificate',
109                        'The passed certificate is self signed and the same '
110                        'certificate cannot be found in the list of trusted '
111                        'certificates.'),
112
113                   19: ('X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN',
114                        'self signed certificate in certificate chain',
115                        'The certificate chain could be built up using the '
116                        'untrusted certificates but the root could not be '
117                        'found locally.'),
118
119                   20: ('X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
120                        'unable to get local issuer certificate',
121                        'The issuer certificate of a locally looked up '
122                        'certificate could not be found. This normally '
123                        'means the list of trusted certificates is not '
124                        'complete.'),
125
126                   21: ('X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE',
127                        'unable to verify the first certificate',
128                        'No signatures could be verified because the chain '
129                        'contains only one certificate and it is not self '
130                        'signed.'),
131
132                   22: ('X509_V_ERR_CERT_CHAIN_TOO_LONG',
133                        'certificate chain too long',
134                        'The certificate chain length is greater than the '
135                        'supplied maximum depth. Unused.'),
136
137                   23: ('X509_V_ERR_CERT_REVOKED',
138                        'certificate revoked',
139                        'The certificate has been revoked. Unused.'),
140
141                   24: ('X509_V_ERR_INVALID_CA',
142                        'invalid CA certificate',
143                        'A CA certificate is invalid. Either it is not a CA '
144                        'or its extensions are not consistent with the '
145                        'supplied purpose.'),
146
147                   25: ('X509_V_ERR_PATH_LENGTH_EXCEEDED',
148                        'path length constraint exceeded',
149                        'The basicConstraints pathlength parameter has been '
150                        'exceeded.'),
151
152                   26: ('X509_V_ERR_INVALID_PURPOSE',
153                        'unsupported certificate purpose',
154                        'The supplied certificate cannot be used for the '
155                        'specified purpose.'),
156
157                   27: ('X509_V_ERR_CERT_UNTRUSTED',
158                        'certificate not trusted',
159                        'The root CA is not marked as trusted for the '
160                        'specified purpose.'),
161
162                   28: ('X509_V_ERR_CERT_REJECTED',
163                        'certificate rejected',
164                        'The root CA is marked to reject the specified '
165                        'purpose.'),
166
167                   29: ('X509_V_ERR_SUBJECT_ISSUER_MISMATCH',
168                        'subject issuer mismatch',
169                        'The current candidate issuer certificate was '
170                        'rejected because its subject name did not match '
171                        'the issuer name of the current certificate. Only '
172                        'displayed when the issuer_checks option is set.'),
173
174                   30: ('X509_V_ERR_AKID_SKID_MISMATCH',
175                        'authority and subject key identifier mismatch',
176                        'The current candidate issuer certificate was '
177                        'rejected because its subject key identifier was '
178                        'present and did not match the authority key '
179                        'identifier current certificate. Only displayed '
180                        'when the issuer_checks option is set.'),
181
182                   31: ('X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH',
183                        'authority and issuer serial number mismatch',
184                        'The current candidate issuer certificate was '
185                        'rejected because its issuer name and serial '
186                        'number was present and did not match the '
187                        'authority key identifier of the current '
188                        'certificate. Only displayed when the issuer_checks '
189                        'option is set.'),
190
191                   32: ('X509_V_ERR_KEYUSAGE_NO_CERTSIGN',
192                        'key usage does not include certificate',
193                        'Signing the current candidate issuer certificate was '
194                        'rejected because its keyUsage extension does not '
195                        'permit certificate signing.'),
196
197                   50: ('X509_V_ERR_APPLICATION_VERIFICATION',
198                        'application verification failure',
199                        'an application specific error. Unused.')}
200
201
202    def __init__(self, cert, errno, depth):
203        VerifyError.__init__(self, cert, errno, depth)
204        self.cert = cert
205        self.errno = errno
206        self.depth = depth
207
208    def __repr__(self):
209        x = self._errorCodes.get(self.errno)
210        if x is not None:
211            name, short, long = x
212            return 'Peer Certificate Verification Failed: %s (error code: %d)' % (
213                long, self.errno
214                )
215        return "Peer Certificate Verification Failed for Unknown Reason"
216
217    __str__ = __repr__
218
219
220_x509names = {
221    'CN': 'commonName',
222    'commonName': 'commonName',
223
224    'O': 'organizationName',
225    'organizationName': 'organizationName',
226
227    'OU': 'organizationalUnitName',
228    'organizationalUnitName': 'organizationalUnitName',
229
230    'L': 'localityName',
231    'localityName': 'localityName',
232
233    'ST': 'stateOrProvinceName',
234    'stateOrProvinceName': 'stateOrProvinceName',
235
236    'C': 'countryName',
237    'countryName': 'countryName',
238
239    'emailAddress': 'emailAddress'}
240
241
242class DistinguishedName(dict):
243    """
244    Identify and describe an entity.
245
246    Distinguished names are used to provide a minimal amount of identifying
247    information about a certificate issuer or subject.  They are commonly
248    created with one or more of the following fields::
249
250        commonName (CN)
251        organizationName (O)
252        organizationalUnitName (OU)
253        localityName (L)
254        stateOrProvinceName (ST)
255        countryName (C)
256        emailAddress
257    """
258    __slots__ = ()
259
260    def __init__(self, **kw):
261        for k, v in kw.iteritems():
262            setattr(self, k, v)
263
264
265    def _copyFrom(self, x509name):
266        d = {}
267        for name in _x509names:
268            value = getattr(x509name, name, None)
269            if value is not None:
270                setattr(self, name, value)
271
272
273    def _copyInto(self, x509name):
274        for k, v in self.iteritems():
275            setattr(x509name, k, v)
276
277
278    def __repr__(self):
279        return '<DN %s>' % (dict.__repr__(self)[1:-1])
280
281
282    def __getattr__(self, attr):
283        try:
284            return self[_x509names[attr]]
285        except KeyError:
286            raise AttributeError(attr)
287
288
289    def __setattr__(self, attr, value):
290        assert type(attr) is str
291        if not attr in _x509names:
292            raise AttributeError("%s is not a valid OpenSSL X509 name field" % (attr,))
293        realAttr = _x509names[attr]
294        value = value.encode('ascii')
295        assert type(value) is str
296        self[realAttr] = value
297
298
299    def inspect(self):
300        """
301        Return a multi-line, human-readable representation of this DN.
302        """
303        l = []
304        lablen = 0
305        def uniqueValues(mapping):
306            return dict.fromkeys(mapping.itervalues()).keys()
307        for k in uniqueValues(_x509names):
308            label = util.nameToLabel(k)
309            lablen = max(len(label), lablen)
310            v = getattr(self, k, None)
311            if v is not None:
312                l.append((label, v))
313        lablen += 2
314        for n, (label, attr) in enumerate(l):
315            l[n] = (label.rjust(lablen)+': '+ attr)
316        return '\n'.join(l)
317
318DN = DistinguishedName
319
320
321class CertBase:
322    def __init__(self, original):
323        self.original = original
324
325    def _copyName(self, suffix):
326        dn = DistinguishedName()
327        dn._copyFrom(getattr(self.original, 'get_'+suffix)())
328        return dn
329
330    def getSubject(self):
331        """
332        Retrieve the subject of this certificate.
333
334        @rtype: L{DistinguishedName}
335        @return: A copy of the subject of this certificate.
336        """
337        return self._copyName('subject')
338
339
340
341def problemsFromTransport(tpt):
342    """
343    Retrieve the SSL errors associated with the given transport.
344
345    @type tpt: L{ISystemHandle} provider wrapper around an SSL connection.
346    @rtype: C{list} of L{OpenSSLVerifyError}.
347    """
348    return tpt.getHandle().get_context().get_app_data().problems
349
350
351def _handleattrhelper(Class, transport, methodName):
352    """
353    (private) Helper for L{Certificate.peerFromTransport} and
354    L{Certificate.hostFromTransport} which checks for incompatible handle types
355    and null certificates and raises the appropriate exception or returns the
356    appropriate certificate object.
357    """
358    method = getattr(transport.getHandle(),
359                     "get_%s_certificate" % (methodName,), None)
360    if method is None:
361        raise CertificateError(
362            "non-TLS transport %r did not have %s certificate" % (transport, methodName))
363    cert = method()
364    if cert is None:
365        raise CertificateError(
366            "TLS transport %r did not have %s certificate" % (transport, methodName))
367    return Class(cert)
368
369
370class Certificate(CertBase):
371    """
372    An x509 certificate.
373    """
374    def __repr__(self):
375        return '<%s Subject=%s Issuer=%s>' % (self.__class__.__name__,
376                                              self.getSubject().commonName,
377                                              self.getIssuer().commonName)
378
379    def __eq__(self, other):
380        if isinstance(other, Certificate):
381            return self.dump() == other.dump()
382        return False
383
384
385    def __ne__(self, other):
386        return not self.__eq__(other)
387
388
389    def load(Class, requestData, format=crypto.FILETYPE_ASN1, args=()):
390        """
391        Load a certificate from an ASN.1- or PEM-format string.
392
393        @rtype: C{Class}
394        """
395        return Class(crypto.load_certificate(format, requestData), *args)
396    load = classmethod(load)
397    _load = load
398
399
400    def dumpPEM(self):
401        """
402        Dump this certificate to a PEM-format data string.
403
404        @rtype: C{str}
405        """
406        return self.dump(crypto.FILETYPE_PEM)
407
408
409    def loadPEM(Class, data):
410        """
411        Load a certificate from a PEM-format data string.
412
413        @rtype: C{Class}
414        """
415        return Class.load(data, crypto.FILETYPE_PEM)
416    loadPEM = classmethod(loadPEM)
417
418
419    def peerFromTransport(Class, transport):
420        """
421        Get the certificate for the remote end of the given transport.
422
423        @type: L{ISystemHandle}
424        @rtype: C{Class}
425
426        @raise: L{CertificateError}, if the given transport does not have a peer
427        certificate.
428        """
429        return _handleattrhelper(Class, transport, 'peer')
430    peerFromTransport = classmethod(peerFromTransport)
431
432
433    def hostFromTransport(Class, transport):
434        """
435        Get the certificate for the local end of the given transport.
436
437        @param transport: an L{ISystemHandle} provider; the transport we will
438
439        @rtype: C{Class}
440
441        @raise: L{CertificateError}, if the given transport does not have a host
442        certificate.
443        """
444        return _handleattrhelper(Class, transport, 'host')
445    hostFromTransport = classmethod(hostFromTransport)
446
447
448    def getPublicKey(self):
449        """
450        Get the public key for this certificate.
451
452        @rtype: L{PublicKey}
453        """
454        return PublicKey(self.original.get_pubkey())
455
456
457    def dump(self, format=crypto.FILETYPE_ASN1):
458        return crypto.dump_certificate(format, self.original)
459
460
461    def serialNumber(self):
462        """
463        Retrieve the serial number of this certificate.
464
465        @rtype: C{int}
466        """
467        return self.original.get_serial_number()
468
469
470    def digest(self, method='md5'):
471        """
472        Return a digest hash of this certificate using the specified hash
473        algorithm.
474
475        @param method: One of C{'md5'} or C{'sha'}.
476        @rtype: C{str}
477        """
478        return self.original.digest(method)
479
480
481    def _inspect(self):
482        return '\n'.join(['Certificate For Subject:',
483                          self.getSubject().inspect(),
484                          '\nIssuer:',
485                          self.getIssuer().inspect(),
486                          '\nSerial Number: %d' % self.serialNumber(),
487                          'Digest: %s' % self.digest()])
488
489
490    def inspect(self):
491        """
492        Return a multi-line, human-readable representation of this
493        Certificate, including information about the subject, issuer, and
494        public key.
495        """
496        return '\n'.join((self._inspect(), self.getPublicKey().inspect()))
497
498
499    def getIssuer(self):
500        """
501        Retrieve the issuer of this certificate.
502
503        @rtype: L{DistinguishedName}
504        @return: A copy of the issuer of this certificate.
505        """
506        return self._copyName('issuer')
507
508
509    def options(self, *authorities):
510        raise NotImplementedError('Possible, but doubtful we need this yet')
511
512
513
514class CertificateRequest(CertBase):
515    """
516    An x509 certificate request.
517
518    Certificate requests are given to certificate authorities to be signed and
519    returned resulting in an actual certificate.
520    """
521    def load(Class, requestData, requestFormat=crypto.FILETYPE_ASN1):
522        req = crypto.load_certificate_request(requestFormat, requestData)
523        dn = DistinguishedName()
524        dn._copyFrom(req.get_subject())
525        if not req.verify(req.get_pubkey()):
526            raise VerifyError("Can't verify that request for %r is self-signed." % (dn,))
527        return Class(req)
528    load = classmethod(load)
529
530
531    def dump(self, format=crypto.FILETYPE_ASN1):
532        return crypto.dump_certificate_request(format, self.original)
533
534
535
536class PrivateCertificate(Certificate):
537    """
538    An x509 certificate and private key.
539    """
540    def __repr__(self):
541        return Certificate.__repr__(self) + ' with ' + repr(self.privateKey)
542
543
544    def _setPrivateKey(self, privateKey):
545        if not privateKey.matches(self.getPublicKey()):
546            raise VerifyError(
547                "Sanity check failed: Your certificate was not properly signed.")
548        self.privateKey = privateKey
549        return self
550
551
552    def newCertificate(self, newCertData, format=crypto.FILETYPE_ASN1):
553        """
554        Create a new L{PrivateCertificate} from the given certificate data and
555        this instance's private key.
556        """
557        return self.load(newCertData, self.privateKey, format)
558
559
560    def load(Class, data, privateKey, format=crypto.FILETYPE_ASN1):
561        return Class._load(data, format)._setPrivateKey(privateKey)
562    load = classmethod(load)
563
564
565    def inspect(self):
566        return '\n'.join([Certificate._inspect(self),
567                          self.privateKey.inspect()])
568
569
570    def dumpPEM(self):
571        """
572        Dump both public and private parts of a private certificate to
573        PEM-format data.
574        """
575        return self.dump(crypto.FILETYPE_PEM) + self.privateKey.dump(crypto.FILETYPE_PEM)
576
577
578    def loadPEM(Class, data):
579        """
580        Load both private and public parts of a private certificate from a
581        chunk of PEM-format data.
582        """
583        return Class.load(data, KeyPair.load(data, crypto.FILETYPE_PEM),
584                          crypto.FILETYPE_PEM)
585    loadPEM = classmethod(loadPEM)
586
587
588    def fromCertificateAndKeyPair(Class, certificateInstance, privateKey):
589        privcert = Class(certificateInstance.original)
590        return privcert._setPrivateKey(privateKey)
591    fromCertificateAndKeyPair = classmethod(fromCertificateAndKeyPair)
592
593
594    def options(self, *authorities):
595        options = dict(privateKey=self.privateKey.original,
596                       certificate=self.original)
597        if authorities:
598            options.update(dict(verify=True,
599                                requireCertificate=True,
600                                caCerts=[auth.original for auth in authorities]))
601        return OpenSSLCertificateOptions(**options)
602
603
604    def certificateRequest(self, format=crypto.FILETYPE_ASN1,
605                           digestAlgorithm='md5'):
606        return self.privateKey.certificateRequest(
607            self.getSubject(),
608            format,
609            digestAlgorithm)
610
611
612    def signCertificateRequest(self,
613                               requestData,
614                               verifyDNCallback,
615                               serialNumber,
616                               requestFormat=crypto.FILETYPE_ASN1,
617                               certificateFormat=crypto.FILETYPE_ASN1):
618        issuer = self.getSubject()
619        return self.privateKey.signCertificateRequest(
620            issuer,
621            requestData,
622            verifyDNCallback,
623            serialNumber,
624            requestFormat,
625            certificateFormat)
626
627
628    def signRequestObject(self, certificateRequest, serialNumber,
629                          secondsToExpiry=60 * 60 * 24 * 365, # One year
630                          digestAlgorithm='md5'):
631        return self.privateKey.signRequestObject(self.getSubject(),
632                                                 certificateRequest,
633                                                 serialNumber,
634                                                 secondsToExpiry,
635                                                 digestAlgorithm)
636
637
638class PublicKey:
639    def __init__(self, osslpkey):
640        self.original = osslpkey
641        req1 = crypto.X509Req()
642        req1.set_pubkey(osslpkey)
643        self._emptyReq = crypto.dump_certificate_request(crypto.FILETYPE_ASN1, req1)
644
645
646    def matches(self, otherKey):
647        return self._emptyReq == otherKey._emptyReq
648
649
650    # XXX This could be a useful method, but sometimes it triggers a segfault,
651    # so we'll steer clear for now.
652#     def verifyCertificate(self, certificate):
653#         """
654#         returns None, or raises a VerifyError exception if the certificate
655#         could not be verified.
656#         """
657#         if not certificate.original.verify(self.original):
658#             raise VerifyError("We didn't sign that certificate.")
659
660    def __repr__(self):
661        return '<%s %s>' % (self.__class__.__name__, self.keyHash())
662
663
664    def keyHash(self):
665        """
666        MD5 hex digest of signature on an empty certificate request with this
667        key.
668        """
669        return md5.md5(self._emptyReq).hexdigest()
670
671
672    def inspect(self):
673        return 'Public Key with Hash: %s' % (self.keyHash(),)
674
675
676
677class KeyPair(PublicKey):
678
679    def load(Class, data, format=crypto.FILETYPE_ASN1):
680        return Class(crypto.load_privatekey(format, data))
681    load = classmethod(load)
682
683
684    def dump(self, format=crypto.FILETYPE_ASN1):
685        return crypto.dump_privatekey(format, self.original)
686
687
688    def __getstate__(self):
689        return self.dump()
690
691
692    def __setstate__(self, state):
693        self.__init__(crypto.load_privatekey(crypto.FILETYPE_ASN1, state))
694
695
696    def inspect(self):
697        t = self.original.type()
698        if t == crypto.TYPE_RSA:
699            ts = 'RSA'
700        elif t == crypto.TYPE_DSA:
701            ts = 'DSA'
702        else:
703            ts = '(Unknown Type!)'
704        L = (self.original.bits(), ts, self.keyHash())
705        return '%s-bit %s Key Pair with Hash: %s' % L
706
707
708    def generate(Class, kind=crypto.TYPE_RSA, size=1024):
709        pkey = crypto.PKey()
710        pkey.generate_key(kind, size)
711        return Class(pkey)
712
713
714    def newCertificate(self, newCertData, format=crypto.FILETYPE_ASN1):
715        return PrivateCertificate.load(newCertData, self, format)
716    generate = classmethod(generate)
717
718
719    def requestObject(self, distinguishedName, digestAlgorithm='md5'):
720        req = crypto.X509Req()
721        req.set_pubkey(self.original)
722        distinguishedName._copyInto(req.get_subject())
723        req.sign(self.original, digestAlgorithm)
724        return CertificateRequest(req)
725
726
727    def certificateRequest(self, distinguishedName,
728                           format=crypto.FILETYPE_ASN1,
729                           digestAlgorithm='md5'):
730        """Create a certificate request signed with this key.
731
732        @return: a string, formatted according to the 'format' argument.
733        """
734        return self.requestObject(distinguishedName, digestAlgorithm).dump(format)
735
736
737    def signCertificateRequest(self,
738                               issuerDistinguishedName,
739                               requestData,
740                               verifyDNCallback,
741                               serialNumber,
742                               requestFormat=crypto.FILETYPE_ASN1,
743                               certificateFormat=crypto.FILETYPE_ASN1,
744                               secondsToExpiry=60 * 60 * 24 * 365, # One year
745                               digestAlgorithm='md5'):
746        """
747        Given a blob of certificate request data and a certificate authority's
748        DistinguishedName, return a blob of signed certificate data.
749
750        If verifyDNCallback returns a Deferred, I will return a Deferred which
751        fires the data when that Deferred has completed.
752        """
753        hlreq = CertificateRequest.load(requestData, requestFormat)
754
755        dn = hlreq.getSubject()
756        vval = verifyDNCallback(dn)
757
758        def verified(value):
759            if not value:
760                raise VerifyError("DN callback %r rejected request DN %r" % (verifyDNCallback, dn))
761            return self.signRequestObject(issuerDistinguishedName, hlreq,
762                                          serialNumber, secondsToExpiry, digestAlgorithm).dump(certificateFormat)
763
764        if isinstance(vval, Deferred):
765            return vval.addCallback(verified)
766        else:
767            return verified(vval)
768
769
770    def signRequestObject(self,
771                          issuerDistinguishedName,
772                          requestObject,
773                          serialNumber,
774                          secondsToExpiry=60 * 60 * 24 * 365, # One year
775                          digestAlgorithm='md5'):
776        """
777        Sign a CertificateRequest instance, returning a Certificate instance.
778        """
779        req = requestObject.original
780        dn = requestObject.getSubject()
781        cert = crypto.X509()
782        issuerDistinguishedName._copyInto(cert.get_issuer())
783        cert.set_subject(req.get_subject())
784        cert.set_pubkey(req.get_pubkey())
785        cert.gmtime_adj_notBefore(0)
786        cert.gmtime_adj_notAfter(secondsToExpiry)
787        cert.set_serial_number(serialNumber)
788        cert.sign(self.original, digestAlgorithm)
789        return Certificate(cert)
790
791
792    def selfSignedCert(self, serialNumber, **kw):
793        dn = DN(**kw)
794        return PrivateCertificate.fromCertificateAndKeyPair(
795            self.signRequestObject(dn, self.requestObject(dn), serialNumber),
796            self)
797
798
799
800class OpenSSLCertificateOptions(object):
801    """
802    A factory for SSL context objects for both SSL servers and clients.
803    """
804
805    _context = None
806    # Older versions of PyOpenSSL didn't provide OP_ALL.  Fudge it here, just in case.
807    _OP_ALL = getattr(SSL, 'OP_ALL', 0x0000FFFF)
808
809    method = SSL.TLSv1_METHOD
810
811    def __init__(self,
812                 privateKey=None,
813                 certificate=None,
814                 method=None,
815                 verify=False,
816                 caCerts=None,
817                 verifyDepth=9,
818                 requireCertificate=True,
819                 verifyOnce=True,
820                 enableSingleUseKeys=True,
821                 enableSessions=True,
822                 fixBrokenPeers=False):
823        """
824        Create an OpenSSL context SSL connection context factory.
825
826        @param privateKey: A PKey object holding the private key.
827
828        @param certificate: An X509 object holding the certificate.
829
830        @param method: The SSL protocol to use, one of SSLv23_METHOD,
831        SSLv2_METHOD, SSLv3_METHOD, TLSv1_METHOD.  Defaults to TLSv1_METHOD.
832
833        @param verify: If True, verify certificates received from the peer and
834        fail the handshake if verification fails.  Otherwise, allow anonymous
835        sessions and sessions with certificates which fail validation.  By
836        default this is False.
837
838        @param caCerts: List of certificate authority certificates to
839        send to the client when requesting a certificate.  Only used if verify
840        is True, and if verify is True, either this must be specified or
841        caCertsFile must be given.  Since verify is False by default,
842        this is None by default.
843
844        @param verifyDepth: Depth in certificate chain down to which to verify.
845        If unspecified, use the underlying default (9).
846
847        @param requireCertificate: If True, do not allow anonymous sessions.
848
849        @param verifyOnce: If True, do not re-verify the certificate
850        on session resumption.
851
852        @param enableSingleUseKeys: If True, generate a new key whenever
853        ephemeral DH parameters are used to prevent small subgroup attacks.
854
855        @param enableSessions: If True, set a session ID on each context.  This
856        allows a shortened handshake to be used when a known client reconnects.
857
858        @param fixBrokenPeers: If True, enable various non-spec protocol fixes
859        for broken SSL implementations.  This should be entirely safe,
860        according to the OpenSSL documentation, but YMMV.  This option is now
861        off by default, because it causes problems with connections between
862        peers using OpenSSL 0.9.8a.
863        """
864
865        assert (privateKey is None) == (certificate is None), "Specify neither or both of privateKey and certificate"
866        self.privateKey = privateKey
867        self.certificate = certificate
868        if method is not None:
869            self.method = method
870
871        self.verify = verify
872        assert ((verify and caCerts) or
873                (not verify)), "Specify client CA certificate information if and only if enabling certificate verification"
874
875        self.caCerts = caCerts
876        self.verifyDepth = verifyDepth
877        self.requireCertificate = requireCertificate
878        self.verifyOnce = verifyOnce
879        self.enableSingleUseKeys = enableSingleUseKeys
880        self.enableSessions = enableSessions
881        self.fixBrokenPeers = fixBrokenPeers
882
883
884    def __getstate__(self):
885        d = self.__dict__.copy()
886        try:
887            del d['_context']
888        except KeyError:
889            pass
890        return d
891
892
893    def __setstate__(self, state):
894        self.__dict__ = state
895
896
897    def getContext(self):
898        """Return a SSL.Context object.
899        """
900        if self._context is None:
901            self._context = self._makeContext()
902        return self._context
903
904
905    def _makeContext(self):
906        ctx = SSL.Context(self.method)
907        ctx.set_app_data(_SSLApplicationData())
908
909        if self.certificate is not None and self.privateKey is not None:
910            ctx.use_certificate(self.certificate)
911            ctx.use_privatekey(self.privateKey)
912            # Sanity check
913            ctx.check_privatekey()
914
915        verifyFlags = SSL.VERIFY_NONE
916        if self.verify:
917            verifyFlags = SSL.VERIFY_PEER
918            if self.requireCertificate:
919                verifyFlags |= SSL.VERIFY_FAIL_IF_NO_PEER_CERT
920            if self.verifyOnce:
921                verifyFlags |= SSL.VERIFY_CLIENT_ONCE
922            if self.caCerts:
923                store = ctx.get_cert_store()
924                for cert in self.caCerts:
925                    store.add_cert(cert)
926
927        def _trackVerificationProblems(conn,cert,errno,depth,preverify_ok):
928            # retcode is the answer OpenSSL's default verifier would have
929            # given, had we allowed it to run.
930            if not preverify_ok:
931                ctx.get_app_data().problems.append(OpenSSLVerifyError(cert, errno, depth))
932            return preverify_ok
933        ctx.set_verify(verifyFlags, _trackVerificationProblems)
934
935        if self.verifyDepth is not None:
936            ctx.set_verify_depth(self.verifyDepth)
937
938        if self.enableSingleUseKeys:
939            ctx.set_options(SSL.OP_SINGLE_DH_USE)
940
941        if self.fixBrokenPeers:
942            ctx.set_options(self._OP_ALL)
943
944        if self.enableSessions:
945            sessionName = md5.md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
946            ctx.set_session_id(sessionName)
947
948        return ctx
Note: See TracBrowser for help on using the browser.