~landscape/zope3/newer-from-ztk

« back to all changes in this revision

Viewing changes to src/twisted/internet/_sslverify.py

  • Committer: Thomas Hervé
  • Date: 2009-07-08 13:52:04 UTC
  • Revision ID: thomas@canonical.com-20090708135204-df5eesrthifpylf8
Remove twisted copy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- test-case-name: twisted.test.test_sslverify -*-
2
 
# Copyright 2005 Divmod, Inc.  See LICENSE file for details
3
 
 
4
 
import itertools, md5
5
 
from OpenSSL import SSL, crypto
6
 
 
7
 
from twisted.python import reflect, util
8
 
from twisted.internet.defer import Deferred
9
 
from 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
 
 
15
 
class _SSLApplicationData(object):
16
 
    def __init__(self):
17
 
        self.problems = []
18
 
 
19
 
class 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
 
 
242
 
class 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
 
 
318
 
DN = DistinguishedName
319
 
 
320
 
 
321
 
class 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
 
 
341
 
def 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
 
 
351
 
def _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
 
 
370
 
class 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
 
 
514
 
class 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
 
 
536
 
class 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
 
 
638
 
class 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
 
 
677
 
class 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
 
 
800
 
class 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