1 diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py 2 index e6ce187..94ee5eb 100644 3 --- a/third_party/tlslite/tlslite/TLSConnection.py 4 +++ b/third_party/tlslite/tlslite/TLSConnection.py 5 @@ -937,8 +937,8 @@ class TLSConnection(TLSRecordLayer): 6 certChain=None, privateKey=None, reqCert=False, 7 sessionCache=None, settings=None, checker=None, 8 reqCAs=None, tlsIntolerant=0, 9 - signedCertTimestamps=None, 10 - fallbackSCSV=False): 11 + signedCertTimestamps=None, fallbackSCSV=False, 12 + ocspResponse=None): 13 """Perform a handshake in the role of server. 14 15 This function performs an SSL or TLS handshake. Depending on 16 @@ -1014,6 +1014,16 @@ class TLSConnection(TLSRecordLayer): 17 binary 8-bit string) that will be sent as a TLS extension whenever 18 the client announces support for the extension. 19 20 + @type ocspResponse: str 21 + @param ocspResponse: An OCSP response (as a binary 8-bit string) that 22 + will be sent stapled in the handshake whenever the client announces 23 + support for the status_request extension. 24 + Note that the response is sent independent of the ClientHello 25 + status_request extension contents, and is thus only meant for testing 26 + environments. Real OCSP stapling is more complicated as it requires 27 + choosing a suitable response based on the ClientHello status_request 28 + extension contents. 29 + 30 @raise socket.error: If a socket error occurs. 31 @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed 32 without a preceding alert. 33 @@ -1024,7 +1034,7 @@ class TLSConnection(TLSRecordLayer): 34 for result in self.handshakeServerAsync(sharedKeyDB, verifierDB, 35 certChain, privateKey, reqCert, sessionCache, settings, 36 checker, reqCAs, tlsIntolerant, signedCertTimestamps, 37 - fallbackSCSV): 38 + fallbackSCSV, ocspResponse): 39 pass 40 41 42 @@ -1033,7 +1043,7 @@ class TLSConnection(TLSRecordLayer): 43 sessionCache=None, settings=None, checker=None, 44 reqCAs=None, tlsIntolerant=0, 45 signedCertTimestamps=None, 46 - fallbackSCSV=False): 47 + fallbackSCSV=False, ocspResponse=None): 48 """Start a server handshake operation on the TLS connection. 49 50 This function returns a generator which behaves similarly to 51 @@ -1053,7 +1063,8 @@ class TLSConnection(TLSRecordLayer): 52 reqCAs=reqCAs, 53 tlsIntolerant=tlsIntolerant, 54 signedCertTimestamps=signedCertTimestamps, 55 - fallbackSCSV=fallbackSCSV) 56 + fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse) 57 + 58 for result in self._handshakeWrapperAsync(handshaker, checker): 59 yield result 60 61 @@ -1062,7 +1073,7 @@ class TLSConnection(TLSRecordLayer): 62 certChain, privateKey, reqCert, 63 sessionCache, settings, reqCAs, 64 tlsIntolerant, signedCertTimestamps, 65 - fallbackSCSV): 66 + fallbackSCSV, ocspResponse): 67 68 self._handshakeStart(client=False) 69 70 @@ -1439,10 +1450,14 @@ class TLSConnection(TLSRecordLayer): 71 sessionID, cipherSuite, certificateType) 72 serverHello.channel_id = clientHello.channel_id 73 if clientHello.support_signed_cert_timestamps: 74 - serverHello.signed_cert_timestamps = signedCertTimestamps 75 + serverHello.signed_cert_timestamps = signedCertTimestamps 76 + serverHello.status_request = (clientHello.status_request and 77 + ocspResponse) 78 doingChannelID = clientHello.channel_id 79 msgs.append(serverHello) 80 msgs.append(Certificate(certificateType).create(serverCertChain)) 81 + if serverHello.status_request: 82 + msgs.append(CertificateStatus().create(ocspResponse)) 83 if reqCert and reqCAs: 84 msgs.append(CertificateRequest().create([], reqCAs)) 85 elif reqCert: 86 diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py 87 index 23e3dcb..d027ef5 100644 88 --- a/third_party/tlslite/tlslite/constants.py 89 +++ b/third_party/tlslite/tlslite/constants.py 90 @@ -22,6 +22,7 @@ class HandshakeType: 91 certificate_verify = 15 92 client_key_exchange = 16 93 finished = 20 94 + certificate_status = 22 95 encrypted_extensions = 203 96 97 class ContentType: 98 @@ -31,7 +32,11 @@ class ContentType: 99 application_data = 23 100 all = (20,21,22,23) 101 102 +class CertificateStatusType: 103 + ocsp = 1 104 + 105 class ExtensionType: 106 + status_request = 5 # OCSP stapling 107 signed_cert_timestamps = 18 # signed_certificate_timestamp in RFC 6962 108 channel_id = 30031 109 110 diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py 111 index 296f422..497ef60 100644 112 --- a/third_party/tlslite/tlslite/messages.py 113 +++ b/third_party/tlslite/tlslite/messages.py 114 @@ -132,6 +132,7 @@ class ClientHello(HandshakeMsg): 115 self.srp_username = None # a string 116 self.channel_id = False 117 self.support_signed_cert_timestamps = False 118 + self.status_request = False 119 120 def create(self, version, random, session_id, cipher_suites, 121 certificate_types=None, srp_username=None): 122 @@ -182,6 +183,19 @@ class ClientHello(HandshakeMsg): 123 if extLength: 124 raise SyntaxError() 125 self.support_signed_cert_timestamps = True 126 + elif extType == ExtensionType.status_request: 127 + # Extension contents are currently ignored. 128 + # According to RFC 6066, this is not strictly forbidden 129 + # (although it is suboptimal): 130 + # Servers that receive a client hello containing the 131 + # "status_request" extension MAY return a suitable 132 + # certificate status response to the client along with 133 + # their certificate. If OCSP is requested, they 134 + # SHOULD use the information contained in the extension 135 + # when selecting an OCSP responder and SHOULD include 136 + # request_extensions in the OCSP request. 137 + p.getFixBytes(extLength) 138 + self.status_request = True 139 else: 140 p.getFixBytes(extLength) 141 soFar += 4 + extLength 142 @@ -230,6 +244,7 @@ class ServerHello(HandshakeMsg): 143 self.compression_method = 0 144 self.channel_id = False 145 self.signed_cert_timestamps = None 146 + self.status_request = False 147 148 def create(self, version, random, session_id, cipher_suite, 149 certificate_type): 150 @@ -282,6 +297,9 @@ class ServerHello(HandshakeMsg): 151 if self.signed_cert_timestamps: 152 extLength += 4 + len(self.signed_cert_timestamps) 153 154 + if self.status_request: 155 + extLength += 4 156 + 157 if extLength != 0: 158 w.add(extLength, 2) 159 160 @@ -299,6 +317,10 @@ class ServerHello(HandshakeMsg): 161 w.add(ExtensionType.signed_cert_timestamps, 2) 162 w.addVarSeq(stringToBytes(self.signed_cert_timestamps), 1, 2) 163 164 + if self.status_request: 165 + w.add(ExtensionType.status_request, 2) 166 + w.add(0, 2) 167 + 168 return HandshakeMsg.postWrite(self, w, trial) 169 170 class Certificate(HandshakeMsg): 171 @@ -367,6 +389,37 @@ class Certificate(HandshakeMsg): 172 raise AssertionError() 173 return HandshakeMsg.postWrite(self, w, trial) 174 175 +class CertificateStatus(HandshakeMsg): 176 + def __init__(self): 177 + self.contentType = ContentType.handshake 178 + 179 + def create(self, ocsp_response): 180 + self.ocsp_response = ocsp_response 181 + return self 182 + 183 + # Defined for the sake of completeness, even though we currently only 184 + # support sending the status message (server-side), not requesting 185 + # or receiving it (client-side). 186 + def parse(self, p): 187 + p.startLengthCheck(3) 188 + status_type = p.get(1) 189 + # Only one type is specified, so hardwire it. 190 + if status_type != CertificateStatusType.ocsp: 191 + raise SyntaxError() 192 + ocsp_response = p.getVarBytes(3) 193 + if not ocsp_response: 194 + # Can't be empty 195 + raise SyntaxError() 196 + self.ocsp_response = ocsp_response 197 + return self 198 + 199 + def write(self, trial=False): 200 + w = HandshakeMsg.preWrite(self, HandshakeType.certificate_status, 201 + trial) 202 + w.add(CertificateStatusType.ocsp, 1) 203 + w.addVarSeq(stringToBytes(self.ocsp_response), 1, 3) 204 + return HandshakeMsg.postWrite(self, w, trial) 205 + 206 class CertificateRequest(HandshakeMsg): 207 def __init__(self): 208 self.contentType = ContentType.handshake 209