Projet

Général

Profil

0003-misc-rewrite-x509utils-using-modern-API-46984.patch

Benjamin Dauvergne, 24 septembre 2020 18:18

Télécharger (9,54 ko)

Voir les différences:

Subject: [PATCH 3/3] misc: rewrite x509utils using modern API (#46984)

 src/authentic2/saml/x509utils.py | 129 ++++++++++++++++---------------
 tests/test_saml_x509utils.py     |   9 ++-
 2 files changed, 72 insertions(+), 66 deletions(-)
src/authentic2/saml/x509utils.py
19 19
import tempfile
20 20
import os
21 21
import subprocess
22
import stat
23 22
import six
24 23

  
25 24
_openssl = 'openssl'
......
54 53
        return 1, None
55 54

  
56 55

  
57
def _protect_file(fd, filepath):
58
    '''Make a file targeted by a file descriptor readable only by the current user
59

  
60
       It's needed to be sure nobody can read the private key file we manage.
61
    '''
62
    os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR)
63

  
64

  
65 56
def check_key_pair_consistency(publickey=None, privatekey=None):
66 57
    '''Check if two PEM key pair whether they are publickey or certificate, are
67 58
    well formed and related.
68 59
    '''
69
    if publickey and privatekey:
70
        try:
71
            privatekey_file_fd, privatekey_fn = tempfile.mkstemp()
72
            publickey_file_fd, publickey_fn = tempfile.mkstemp()
73
            _protect_file(privatekey_file_fd, privatekey_fn)
74
            _protect_file(publickey_file_fd, publickey_fn)
75
            os.fdopen(privatekey_file_fd, 'w').write(privatekey)
76
            os.fdopen(publickey_file_fd, 'w').write(publickey)
77
            if 'BEGIN CERTIFICATE' in publickey:
78
                rc1, modulus1 = _call_openssl(['x509', '-in', publickey_fn, '-noout', '-modulus'])
79
            else:
80
                rc1, modulus1 = _call_openssl(['rsa', '-pubin', '-in', publickey_fn, '-noout', '-modulus'])
81
                if rc1 != 0:
82
                    rc1, modulus1 = _call_openssl(['dsa', '-pubin', '-in', publickey_fn, '-noout', '-modulus'])
60
    if not publickey or not privatekey:
61
        return None
62

  
63
    privatekey_file = tempfile.NamedTemporaryFile(mode='w')
64
    publickey_file = tempfile.NamedTemporaryFile(mode='w')
65
    with privatekey_file, publickey_file:
66

  
67
        privatekey_file.write(privatekey)
68
        privatekey_file.flush()
69
        publickey_file.write(publickey)
70
        publickey_file.flush()
83 71

  
72
        if 'BEGIN CERTIFICATE' in publickey:
73
            rc1, modulus1 = _call_openssl(['x509', '-in', publickey_file.name, '-noout', '-modulus'])
74
        else:
75
            rc1, modulus1 = _call_openssl(['rsa', '-pubin', '-in', publickey_file.name, '-noout', '-modulus'])
84 76
            if rc1 != 0:
85
                return False
77
                rc1, modulus1 = _call_openssl(['dsa', '-pubin', '-in', publickey_file.name, '-noout', '-modulus'])
86 78

  
87
            rc2, modulus2 = _call_openssl(['rsa', '-in', privatekey_fn, '-noout', '-modulus'])
88
            if rc2 != 0:
89
                rc2, modulus2 = _call_openssl(['dsa', '-in', privatekey_fn, '-noout', '-modulus'])
79
        if rc1 != 0:
80
            return False
90 81

  
91
            if rc1 == 0 and rc2 == 0 and modulus1 == modulus2:
92
                return True
93
            else:
94
                return False
95
        finally:
96
            os.unlink(privatekey_fn)
97
            os.unlink(publickey_fn)
98
    return None
82
        rc2, modulus2 = _call_openssl(['rsa', '-in', privatekey_file.name, '-noout', '-modulus'])
83
        if rc2 != 0:
84
            rc2, modulus2 = _call_openssl(['dsa', '-in', privatekey_file.name, '-noout', '-modulus'])
85

  
86
        if rc1 == 0 and rc2 == 0 and modulus1 == modulus2:
87
            return True
88
        else:
89
            return False
99 90

  
100 91

  
101 92
def generate_rsa_keypair(numbits=1024):
102 93
    '''Generate simple RSA public and private key files
103 94
    '''
104
    try:
105
        privatekey_file_fd, privatekey_fn = tempfile.mkstemp()
106
        publickey_file_fd, publickey_fn = tempfile.mkstemp()
107
        _protect_file(privatekey_file_fd, privatekey_fn)
108
        _protect_file(publickey_file_fd, publickey_fn)
109
        rc1, _ = _call_openssl(['genrsa', '-out', privatekey_fn, '-passout', 'pass:', str(numbits)])
110
        rc2, _ = _call_openssl(['rsa', '-in', privatekey_fn, '-pubout', '-out', publickey_fn])
111
        if rc1 != 0 or rc2 != 0:
95
    privatekey_file = tempfile.NamedTemporaryFile(mode='r')
96
    publickey_file = tempfile.NamedTemporaryFile(mode='r')
97

  
98
    with privatekey_file, publickey_file:
99
        rc1, _ = _call_openssl(['genrsa', '-out', privatekey_file.name, '-passout', 'pass:', str(numbits)])
100
        if rc1 != 0:
101
            raise Exception('Failed to generate a key')
102
        rc2, _ = _call_openssl(['rsa', '-in', privatekey_file.name, '-pubout', '-out', publickey_file.name])
103
        if rc2 != 0:
112 104
            raise Exception('Failed to generate a key')
113
        return (os.fdopen(publickey_file_fd).read(), os.fdopen(privatekey_file_fd).read())
114
    finally:
115
        os.unlink(privatekey_fn)
116
        os.unlink(publickey_fn)
105
        return (publickey_file.read(), privatekey_file.read())
117 106

  
118 107

  
119 108
def get_rsa_public_key_modulus(publickey):
120
    try:
121
        publickey_file_fd, publickey_fn = tempfile.mkstemp()
122
        os.fdopen(publickey_file_fd, 'w').write(publickey)
109
    publickey_file = tempfile.NamedTemporaryFile(mode='w')
110

  
111
    with publickey_file:
112
        publickey_file.write(publickey)
113
        publickey_file.flush()
114

  
123 115
        if 'BEGIN PUBLIC' in publickey:
124
            rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_fn, '-noout', '-modulus'])
116
            rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_file.name, '-noout', '-modulus'])
125 117
        elif 'BEGIN RSA PRIVATE KEY' in publickey:
126
            rc, modulus = _call_openssl(['rsa', '-in', publickey_fn, '-noout', '-modulus'])
118
            rc, modulus = _call_openssl(['rsa', '-in', publickey_file.name, '-noout', '-modulus'])
127 119
        elif 'BEGIN CERTIFICATE' in publickey:
128
            rc, modulus = _call_openssl(['x509', '-in', publickey_fn, '-noout', '-modulus'])
120
            rc, modulus = _call_openssl(['x509', '-in', publickey_file.name, '-noout', '-modulus'])
129 121
        else:
130 122
            return None
123

  
131 124
        i = modulus.find('=')
125

  
132 126
        if rc == 0 and i:
133 127
            return int(modulus[i + 1:].strip(), 16)
134
    finally:
135
        os.unlink(publickey_fn)
136 128
    return None
137 129

  
138 130

  
139 131
def get_rsa_public_key_exponent(publickey):
140
    try:
141
        publickey_file_fd, publickey_fn = tempfile.mkstemp()
142
        os.fdopen(publickey_file_fd, 'w').write(publickey)
132
    publickey_file = tempfile.NamedTemporaryFile(mode='w')
133

  
134
    with publickey_file:
135
        publickey_file.write(publickey)
136
        publickey_file.flush()
137

  
143 138
        _exponent = 'Exponent: '
144 139
        if 'BEGIN PUBLIC' in publickey:
145
            rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_fn, '-noout', '-text'])
140
            rc, modulus = _call_openssl(['rsa', '-pubin', '-in', publickey_file.name, '-noout', '-text'])
146 141
        elif 'BEGIN RSA PRIVATE' in publickey:
147
            rc, modulus = _call_openssl(['rsa', '-in', publickey_fn, '-noout', '-text'])
142
            rc, modulus = _call_openssl(['rsa', '-in', publickey_file.name, '-noout', '-text'])
148 143
            _exponent = 'publicExponent: '
149 144
        elif 'BEGIN CERTIFICATE' in publickey:
150
            rc, modulus = _call_openssl(['x509', '-in', publickey_fn, '-noout', '-text'])
145
            rc, modulus = _call_openssl(['x509', '-in', publickey_file.name, '-noout', '-text'])
151 146
        else:
152 147
            return None
153 148
        i = modulus.find(_exponent)
154 149
        j = modulus.find('(', i)
155 150
        if rc == 0 and i and j:
156 151
            return int(modulus[i + len(_exponent):j].strip())
157
    finally:
158
        os.unlink(publickey_fn)
159 152
    return None
160 153

  
161 154

  
......
178 171

  
179 172
    mod = get_rsa_public_key_modulus(publickey)
180 173
    exp = get_rsa_public_key_exponent(publickey)
174
    mod_byte_length = (mod.bit_length() + 7) // 8
175
    exp_byte_length = (exp.bit_length() + 7) // 8
176
    mod_bytes = mod.to_bytes(mod_byte_length, byteorder='big')
177
    exp_bytes = exp.to_bytes(exp_byte_length, byteorder='big')
178
    mod_cryptobinary = base64.b64encode(mod_bytes).decode('ascii')
179
    exp_cryptobinary = base64.b64encode(exp_bytes).decode('ascii')
181 180
    return (
182 181
        '<RSAKeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">\n\t'
183 182
        '<Modulus>%s</Modulus>\n\t'
184 183
        '<Exponent>%s</Exponent>\n</RSAKeyValue>' % (
185
            base64.b64encode(int_to_bin(mod)), base64.b64encode(int_to_bin(exp))))
184
            mod_cryptobinary,
185
            exp_cryptobinary)
186
    )
tests/test_saml_x509utils.py
68 68
8eM47A92x9uplD/sN550pTKM7XLhHBvEfLujUoGHpWQxGA==
69 69
-----END RSA PRIVATE KEY-----'''
70 70
    assert check_key_pair_consistency(cert, key)
71
    assert get_xmldsig_rsa_key_value(cert)
71
    assert get_xmldsig_rsa_key_value(cert) == '''\
72
<RSAKeyValue xmlns="http://www.w3.org/2000/09/xmldsig#">
73
	<Modulus>rU2w03vy6w/oLytEoH/657wIOM3HP7yXBHbIhrCd7IU7Huzj3+XyGg+5a8vo5rRV+tZ/EZ9XdYsPsIbmG6xukdzoQ8OdL7n29ka0UhwTgOwnH4ikA+gk9qd9ZrL/goh2xpqB0Rcrdgp0RsthQl9jos3+asX4x2iRF7tLZP0nTdk=</Modulus>
74
	<Exponent>AQAB</Exponent>
75
</RSAKeyValue>'''
76
    assert get_rsa_public_key_modulus(cert) is not None
77
    assert get_rsa_public_key_exponent(cert) is not None
72 78
    assert len(decapsulate_pem_file(key).splitlines()) == len(key.splitlines()) - 2
73

  
74
-