Skip to content

Commit

Permalink
fix: Update cleaning regex to match RUTs with non-numeric digits
Browse files Browse the repository at this point in the history
- The regular expression in `get_subject_rut_from_certificate_pfx` caused the removal of all letters,
including the letter K, from the RUTs.
- It has been updated to a regex that includes the letter K in certain RUTs.
- Added tests for RUTs that end with a `K`.
- Added a guide named `howto.md`, which explains how to create a valid `.der` certificate.
  Based on the guide in `FD-CL-Data`
  [See](https://github.com/cordada/fd-cl-data/blob/ba85835e81c857acbcc0498751c21335591b17b5/test_data/apps/sii_auth/certificate_pfx/howto.md).

Ref: #700
Ref: https://app.shortcut.com/cordada/story/9821
  • Loading branch information
svillegas-cdd committed Oct 2, 2024
1 parent b39402e commit 2eb9a88
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 1 deletion.
10 changes: 9 additions & 1 deletion src/cl_sii/rut/crypto_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ def get_subject_rut_from_certificate_pfx(pfx_file_bytes: bytes, password: Option
raise Exception(f'len(results) == {len(results)}')

subject_rut_raw: bytes = results[0]
subject_rut = re.sub(r'[^0-9-]', '', subject_rut_raw.decode('utf-8'))
subject_rut_str = subject_rut_raw.decode('utf-8')

# Regex to extract Chilean RUT formatted string
rut_match = re.search(r'\b\d{1,8}-[0-9Kk]\b', subject_rut_str)

if not rut_match:
raise Exception('RUT format not found in certificate')

subject_rut = rut_match.group(0)

return Rut(subject_rut)
Binary file not shown.
28 changes: 28 additions & 0 deletions src/tests/test_data/sii-crypto/TEST-DTE-13185095-K.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJdYOEZnh0gmB5
hUfDzS/5oq9u0CXZ+xFozZyw+27R0frwlUioe9Xyyhzx1PyUsp3OLddI18zxLf3s
0ZP9KdoQd43P90P+oVqkQkQgt9fCabWU7SFKZEXZXAi36ubVvuOA/MgKKrcny59w
elucNoP0CbBVElLMDBIjdF6eoXykZI4LsHdU5cQ8SDGC3qmtPTl7oikZ6lGTrNXO
egoMP/rz6b6O9MJ6CdDmLCgI3zzuTlYdScXv2nNz/p424liRNXurw/5k9ouLHhb0
j25IQV+jdz2XVvyNKSPZBINxeU8ojzrW/8y8+9lNOLUDjvA257h234YY+7nEmDy6
JecHLQKlAgMBAAECggEABne3WTDQ/SySXFRjEW4s9B688xnLnUvqKysutJ/d1u6e
18pzIrWXEMxcUYc89KknV88w8i27bqLDXC7+SUpmrdCoxNxzWmFjv5JBDavZSWyL
X9SdFP5TH79MqFrqPkJ6m1GCOpFUf/qRi9LhzgoSAmutNY35CoP4sRqzTvRwQ/bH
4JR2mO1GD3mDvPwUpsONucujuQCpNhalgLCf2OQIG6nfHU1koJawSps8dHvqjf/g
K8x37MtE/vF+ubdyFVRkx6wv3YCaieP4lac9sOrPu7X9dtYDli8yCjJ6waILRilI
4KXL/bu+hNIw3entuB8V5V5uPP4PrQwZ43VwuabrAQKBgQDZ9Buo5B739GpL468O
ORKrHOPT1j1BOQ2Wz0V3+SbgM1CnRJ19QWIAxqLv8jRWd2o9QWm0UaEr4MpyIo2C
ZMYsIL0ALz9i39WXumwWziIiCpC5ABYt882YZX4nzhJDgt01MnVvLJzCb8J/oJdO
/un3/8maq1nVHNtdhsM9BbeNDQKBgQDsoEzgR2xlf2bA0NnAGKSoACi74NS0COAG
nxF2oq/bhPsQk8UHK5ka6otHsl0lgFRCRG+tNLWnq7jWB+ZhwoVxHeQB5ddGil6V
atQXNuW7V/Xy+CsZCe5/mekKWNdcacOo76cAqbYtLyPAkVl/381S53jEE47Us+6k
2eptxC3V+QKBgEJp0eva51zjC2jojjUlSvz9JqcsRyoSuoNT0XVHZIM438C4dczv
GW/nF0tKYIxgguz7e7xIi3YVX1r8EGbFUmWr7CucOhJk5m7/jWQ9l8ULtyHIVvnV
qrZfZtu2PXZ47/L/1yzzSSkuaPP++VxG7QB23vXUdOEtk+Kh5+g2T8IZAoGAAPij
eCQy6LO+KzpwOl6fhmUBxculc9u5d619d9wxFpiUIzxICcB/D2I5EiFESpwdPGxl
fPODb13AE3jS1EHlJFK4Fd3opUx6GOjoV/QMu1kgFFA6dQ7aYMGz+CvnLmTsvavG
JrWLnuHbprWyBVlY0WdL0po18t+OMjUGxk6Q1ZkCgYEAznH4XiQo/MHfcSkvUunm
8Hn5LI+aP+kbIg/NExrOQR3mbQaXhpAJzb4+VRX/l5XNvJ2AHv64lSKTgirvK+p7
jmB8+pPC3XZ9nyfWYBj4+GMudVytlbDb0Sxrr9AZK3GQaVW26WBffWALAmClWFFm
bkGfTLjxBHBG6vqhFBGF/Ak=
-----END PRIVATE KEY-----
Binary file not shown.
28 changes: 28 additions & 0 deletions src/tests/test_data/sii-crypto/TEST-DTE-WITH-ID-BUT-NO-RUT.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCcsPQO/KxT8WNj
/pXk9japl0voyDhyN3bNqgqVgWL2jwzllR1SQRw7ja0T4uoFhWf3O3NZyGrnLV7a
K4Rj0IYrMywM6DoEuHW/R0iwO8PPK8JpENg9245GaNB45rICcm1nBBGH46ZhRa+J
VdtBwqFLvqbzbCgFseH10evfcNT2QWRvpXDdkSjejNtSDnFVXeaUNQRa8N2xgnBF
tmhVakMXsqa/RKwr320c1ksO2ukIz8x9xQPtExppSOpGbip4NqhXbEA6yAZQvyzu
UGY3GhA37rTf9ka3HYt4XTz8xokVV21Zj8IceolGUl4vbVLhCFM0aY20qEfp+4Oh
JIs/n3SFAgMBAAECggEAAoNvIsdoTz9lv/6fMmlFprJD2DPP/fsIR5PE8DF/YCOa
yhr6ea2MMaNb5aAD73s8l/Fm8AeAOX2XkinVCZHYeRxsxjc6aQV5dAxFbPhEc5AI
4g0QXuuk7Fm1kF7o95OU0Cx3SIX9Dv3iazJKnlMsKa4g+PIg8ThxfrMzlKW3cMzE
zfWdgGe65I0cOS8kLi7C+nd23y2EMn/Zfq55pguSYq0E49A+J30KzRFmZZWiXsfB
U0Q1mOHEl4Lbl0WLeJnjp+adDTgRwUMoAsuQ87SGr+8BRwZCJX2wLmdBS4NKvZFH
Xsxu4OQxxx8SySxeGKqmyE4cUAL2iCy18vS1wL/5OQKBgQDGjpoe9aU8eEt0vDbe
/SyJITMchnqOUNGEBAyRmPqViGolHd+htnrj3hJ1O44vTjUTxj3NWxon2pFYMrtj
LHBN9CBzt3/1KMjUQmQL1BmIMRlvXS8HsRQl4Nt9lP4GqtX0tbi64JydCENiavL9
zVE0mCV4HzNSqSiTfqEVBZ/NvQKBgQDKBbalPtzQQ+sgvslMQPNpNFCpow4Nn6Eo
CHGQ9nZFFyEpdMxcpqhYwgiy8eosBXTEhbhQyYcbxB77EDH1WLcho1ZII8rX6LrM
153B/8XuIdEkJDkcYhEGmM0CAO+X8Nztkksk3T3jpG8TFdZBlk2giegBV4ko2Ina
HdkRqah6aQKBgEM6mXiOF+qHmJTn/XQ3KNMtiI7KAckaGDao4FCUCZSD4dy7ZrLs
hGOPF5TWG2htBI+zec2EYTDJUpkYZFZJ/6SFWk+T/CFYM9eauyE+KX7xkPkiBgCG
tpm0rtywi+paAaOfu/Kahqys1ZQHPkstL6etNFKdzdTZLcHzCDuD8f3JAoGATDaj
lOuGOjulNJFFN7M5IPNPiu+smY8jKQsmbN3N+HqlVBJwFnP5BqMMzRVeloTobEtW
IYQlqF/woB6X+kshq1sHbeey2ok+D5E4PrvTW+b+E3hm40JL0gVLMfpQaS3A6w9J
sfqVIpAiJz0Ru2SMnIfqMrdnUzV9q/+eqH8sxCECgYBxIN/8r/H1lmJBa8vaAO5P
Nb6j6yRgWkIIS8lN9uGjs5O3qfT0MDvkiyp6vDetHelKF+ayJ+SeNpuj978g2lhy
KgUtUYeo1qXLHHpEpmf/Dc597v+v8aI9uUD3RFdOtR2yup3JUlDVJFf/VtF27a5X
aC5sPUAoOReOMN6lLnxKrg==
-----END PRIVATE KEY-----
71 changes: 71 additions & 0 deletions src/tests/test_data/sii-crypto/howto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Generating a self-signed certificate in DER format using OpenSSL

## Documentation

- <https://www.openssl.org/docs/manmaster/man1/req.html>

## Parameters

- File to send the key to (`key_file_name`)
- Output file (`certificate_file_name`)
- Number of days cert is valid for (`number_of_days`)

```sh
key_file_name='key.pem'
certificate_file_name='certificate.der'
number_of_days=365
subject_rut_oid='1.3.6.1.4.1.8321.1'
subject_rut='13185095-K'
```

## Steps

### Generate the private key and public certificate

```sh
openssl req \
-newkey rsa:2048 \
-nodes \
-keyout "$key_file_name" \
-x509 \
-days "$number_of_days" \
-outform DER \
-out "$certificate_file_name" \
-extensions san -config <(cat /etc/ssl/openssl.cnf \
<(printf "\n[san]\nsubjectAltName=otherName:$subject_rut_oid;UTF8:$subject_rut"))
```

```text
Generating a RSA private key
....................................................................................+++++
....................................................+++++
writing new private key to 'key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CL
State or Province Name (full name) [Some-State]:Region Metropolitana
Locality Name (eg, city) []:Santiago
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Acme Corporation
Organizational Unit Name (eg, section) []:Acme Explosive Tennis Balls
Common Name (e.g. server FQDN or YOUR name) []:John Doe
Email Address []:john.doe@acme.com
```

### Output

#### Review the created certificate

```sh
openssl x509 \
-inform DER \
-in "$certificate_file_name" \
-text -noout
```

This will generate a self-signed certificate in DER format and allow you to review its contents
40 changes: 40 additions & 0 deletions src/tests/test_rut_crypto_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,46 @@ def test_get_subject_rut_from_certificate_pfx_ok(self) -> None:
self.assertIsInstance(subject_rut, rut.Rut)
self.assertEqual(subject_rut, rut.Rut('13185095-6'))

def test_get_subject_rut_from_certificate_pfx_ok_with_rut_that_ends_with_K(self) -> None:
cert_der_bytes = utils.read_test_file_bytes('test_data/sii-crypto/TEST-DTE-13185095-K.der')

x509_cert = load_der_x509_cert(cert_der_bytes)

with patch.object(
cryptography.hazmat.primitives.serialization.pkcs12,
'load_key_and_certificates',
Mock(return_value=(None, x509_cert, None)),
):
pfx_file_bytes = b'hello'
password = 'fake_password'
subject_rut = get_subject_rut_from_certificate_pfx(
pfx_file_bytes=pfx_file_bytes,
password=password,
)
self.assertIsInstance(subject_rut, rut.Rut)
self.assertEqual(subject_rut, rut.Rut('13185095-K'))

def test_get_subject_rut_from_certificate_pfx_not_matching_rut_format(self) -> None:
cert_der_bytes = utils.read_test_file_bytes(
'test_data/sii-crypto/TEST-DTE-WITH-ID-BUT-NO-RUT.der',
)

x509_cert = load_der_x509_cert(cert_der_bytes)

with patch.object(
pkcs12,
'load_key_and_certificates',
Mock(return_value=(None, x509_cert, None)),
):
pfx_file_bytes = b'hello'
password = 'fake_password'
with self.assertRaises(Exception) as cm:
get_subject_rut_from_certificate_pfx(
pfx_file_bytes=pfx_file_bytes,
password=password,
)
self.assertEqual(cm.exception.args, ('RUT format not found in certificate',))

def test_get_subject_rut_from_certificate_pfx_fails_if_rut_info_is_missing(self) -> None:
cert_der_bytes = utils.read_test_file_bytes(
'test_data/crypto/wildcard-google-com-cert.der',
Expand Down

0 comments on commit 2eb9a88

Please sign in to comment.