summaryrefslogtreecommitdiffstats
path: root/src/lib/tlslite/Session.py
blob: a951f4589429f554e5925f8bbb658a6e660e48e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""Class representing a TLS session."""

from utils.compat import *
from mathtls import *
from constants import *

class Session:
    """
    This class represents a TLS session.

    TLS distinguishes between connections and sessions.  A new
    handshake creates both a connection and a session.  Data is
    transmitted over the connection.

    The session contains a more permanent record of the handshake.  The
    session can be inspected to determine handshake results.  The
    session can also be used to create a new connection through
    "session resumption". If the client and server both support this,
    they can create a new connection based on an old session without
    the overhead of a full handshake.

    The session for a L{tlslite.TLSConnection.TLSConnection} can be
    retrieved from the connection's 'session' attribute.

    @type srpUsername: str
    @ivar srpUsername: The client's SRP username (or None).

    @type sharedKeyUsername: str
    @ivar sharedKeyUsername: The client's shared-key username (or
    None).

    @type clientCertChain: L{tlslite.X509CertChain.X509CertChain} or
    L{cryptoIDlib.CertChain.CertChain}
    @ivar clientCertChain: The client's certificate chain (or None).

    @type serverCertChain: L{tlslite.X509CertChain.X509CertChain} or
    L{cryptoIDlib.CertChain.CertChain}
    @ivar serverCertChain: The server's certificate chain (or None).
    """

    def __init__(self):
        self.masterSecret = createByteArraySequence([])
        self.sessionID = createByteArraySequence([])
        self.cipherSuite = 0
        self.srpUsername = None
        self.sharedKeyUsername = None
        self.clientCertChain = None
        self.serverCertChain = None
        self.resumable = False
        self.sharedKey = False

    def _clone(self):
        other = Session()
        other.masterSecret = self.masterSecret
        other.sessionID = self.sessionID
        other.cipherSuite = self.cipherSuite
        other.srpUsername = self.srpUsername
        other.sharedKeyUsername = self.sharedKeyUsername
        other.clientCertChain = self.clientCertChain
        other.serverCertChain = self.serverCertChain
        other.resumable = self.resumable
        other.sharedKey = self.sharedKey
        return other

    def _calcMasterSecret(self, version, premasterSecret, clientRandom,
                         serverRandom):
        if version == (3,0):
            self.masterSecret = PRF_SSL(premasterSecret,
                                concatArrays(clientRandom, serverRandom), 48)
        elif version in ((3,1), (3,2)):
            self.masterSecret = PRF(premasterSecret, "master secret",
                                concatArrays(clientRandom, serverRandom), 48)
        else:
            raise AssertionError()

    def valid(self):
        """If this session can be used for session resumption.

        @rtype: bool
        @return: If this session can be used for session resumption.
        """
        return self.resumable or self.sharedKey

    def _setResumable(self, boolean):
        #Only let it be set if this isn't a shared key
        if not self.sharedKey:
            #Only let it be set to True if the sessionID is non-null
            if (not boolean) or (boolean and self.sessionID):
                self.resumable = boolean

    def getCipherName(self):
        """Get the name of the cipher used with this connection.

        @rtype: str
        @return: The name of the cipher used with this connection.
        Either 'aes128', 'aes256', 'rc4', or '3des'.
        """
        if self.cipherSuite in CipherSuite.aes128Suites:
            return "aes128"
        elif self.cipherSuite in CipherSuite.aes256Suites:
            return "aes256"
        elif self.cipherSuite in CipherSuite.rc4Suites:
            return "rc4"
        elif self.cipherSuite in CipherSuite.tripleDESSuites:
            return "3des"
        else:
            return None

    def _createSharedKey(self, sharedKeyUsername, sharedKey):
        if len(sharedKeyUsername)>16:
            raise ValueError()
        if len(sharedKey)>47:
            raise ValueError()

        self.sharedKeyUsername = sharedKeyUsername

        self.sessionID = createByteArrayZeros(16)
        for x in range(len(sharedKeyUsername)):
            self.sessionID[x] = ord(sharedKeyUsername[x])

        premasterSecret = createByteArrayZeros(48)
        sharedKey = chr(len(sharedKey)) + sharedKey
        for x in range(48):
            premasterSecret[x] = ord(sharedKey[x % len(sharedKey)])

        self.masterSecret = PRF(premasterSecret, "shared secret",
                                createByteArraySequence([]), 48)
        self.sharedKey = True
        return self