Russia’s certificate authority for sanctioned organizations
🔏

Russia’s certificate authority for sanctioned organizations

📅 Archival Date
Jun 9, 2022 4:59 PM
🏷️ Tags
Россия

After Russia’s invasion of Ukraine, several countries and blocs have imposed sweeping sanctions on Russian companies, banks, and individuals. Anticipating these sanctions, we have seen the Russian government taking steps to reduce their dependence on foreign internet infrastructure.

In early March, the Russian Ministry of Digital Development started recommending users to install a browser that supports the “Russian certificate” if they want to ensure access to all websites and online services. In particular, they mentioned Yandex.Browser and Atom as browsers that already support this certificate.

This special certificate is the root certificate of Russia’s new national certificate authority. They created this certificate authority to support Russian organizations that had their certificates revoked or not renewed due to the sanctions. In the past weeks, well-known public certificate authorities like DigiCert and Sectigo have fully stopped the issuance of certificates with DNS names for Russian top-level domains and certificates for Russian organizations.

In this post, I will discuss why the Russian government created a national certificate authority and why it is asking users to install specific browsers. I will also explain how one of these browsers, Yandex Browser, has implemented support for this certificate authority.

Certificate authorities and root stores

If you visit a website over a secure connection (HTTPS), the server presents the client with a digital certificate. This certificate includes the identity of the website, public keys and signatures that the client uses to verify whether it can be trusted. These digital certificates are issued by certificate authorities.

Operating systems and some browsers ship with a list of certificates of certificate authorities. These are the certificate authorities that are considered trusted. Your browser verifies that a presented certificate “chains back” to one of these root certificates, as depicted in the image below. These lists of root certificates are also known as root stores, and they are managed by root programs. Apple, Microsoft, and Mozilla all operate their own root programs.

image

Browser, root store, and certificate chain

It is clear that the Russian government rushed to set up this certificate authority. It was put together in a matter of weeks, and is therefore not included yet in any of the formal root programs. It is not clear if they eventually intend to follow to the Baseline Requirements, a set of policies and technical requirements for inclusion in root stores.

Since this “Russian certificate” is currently not included in any root store, it is not trusted by any modern operating system or browser. They had to find a way to either get users to install the certificate manually or get them to use a browser that supports this Russian certificate authority out of the box. They worked with two Russian tech companies, Yandex and VK (formerly Mail.ru), to add support for this certificate authority to their browsers.

Yandex Browser

Yandex Browser was the first to add support for Russia’s new certificate authority. Any website that uses a certificate that is signed by this certificate authority is trusted by Yandex Browser. There are several organizations that have already migrated some of their websites to the new certificates, including the National Reserve Bank, as depicted below.

image

Yandex Browser with the website of the National Reserve Bank using the new certificate

Yandex Browser is based on the open-source Chromium platform. At least on macOS, most Chromium derivatives use the operating system’s root store. This is what made me curious to understand how Yandex added support for this custom root certificate.

Reverse engineering

I started by installing the Yandex Browser in a virtual machine running macOS and configured it to forward all HTTP traffic to Burp Proxy. Sifting through all the HTTP requests to Yandex services, I could see the browser retrieving remote configuration files, from allowlisted extensions to URL rewrite rules. What caught my attention was the HTTP request to retrieve a configuration file named custom_root_certs.

image

Yandex Browser HTTP request to retrieve the custom root certificates

Unfortunately, the contents of all configuration files were scrambled. Looking closely at the different configuration files, their response sizes provided a clue. The size of all of them were multiples of 16 bytes, which could be an indication that the contents (16 byte blocks) are encrypted with a common block cipher like AES.

I picked Hopper and LLDB to reverse engineer Yandex Browser and understand how it loads and decrypts the remote configuration files. All the bits that I was interested in were packed up in the Yandex Framework binary. After a bit of puzzling, I learned that the configuration files are encrypted using AES in CBC mode with a 256-bit key.

00000000 ad a5 29 77 9c 87 35 0d 52 79 bd 69 2e a6 06 bf
00000010 f3 20 98 0e a7 7d 3e 84 e8 a0 28 ae 8b d7 a4 0d
...

The first block (of 16 bytes) makes up the initialization vector (IV):

ad a5 29 77 9c 87 35 0d 52 79 bd 69 2e a6 06 bf

All configuration files are encrypted with the same 256-bit encryption key that was hard-coded in the Yandex Framework binary.

2e 35 49 28 6f 52 5b 4c 47 4a 37 67 47 72 34 2a 51 2d 54 77 39 30 4d 38 56 4e 61 36 44 5e 69 6f

Given the encrypted file custom_root_certs, the encryption key and the initialization vector, it can be decrypted using OpenSSL:

tail -c +17 ./custom_root_certs | openssl aes-256-cbc -d \
    -K 2e3549286f525b4c474a37674772342a512d547739304d38564e6136445e696f -iv ada529779c87350d5279bd692ea606bf | less

Configuration container

The plaintext is a JSON document with the following structure:

{
  "version": 1,
  "data": "[data]",
  "signature": "[signature]"
}

It is a JSON-based container where the contents are stored in the data field. In most cases, this is an encoded JSON string itself. In turn, the value of the signature field is a 256-byte signature over the value of the data field. It took me a little while to figure out what signature algorithm was used to produce this signature. It turned out to be digitally signed using a 1024-bit RSA key with a SHA-1 hash function.

Given the data and the signature stored in the files custom_root_certs.dat and custom_root_certs.sig, respectively. The signature can be verified using OpenSSL:

openssl dgst -sha1 -verify pubkey_1024_0xB3C4A10.pem -signature ./custom_root_certs.sig ./custom_root_certs.dat

These configurations are persisted on disk in encrypted form in files named configs_part1.json and configs_part1.json. On macOS, these files can be found in the directory $HOME/Library/Application Support/Yandex/YandexBrowser. It is not clear to me why Yandex went through the effort to encrypt the configuration files other than to obfuscate the contents to make analyzing them a tiny bit harder. The digital signature ensures that the integrity of the configuration files can be verified anyway.

Custom root certificates

In the previous sections I explained how Yandex Browser loads, decrypts and verifies the individual configuration files. For the ‘custom root certificates’ configuration file, find below a simplified representation of the JSON data:

{
  "host_masks": [
    "*.vtb.ru",
    "*.sberbank.ru",
    "*.psbank.ru",
    "*.vtb.com",
    "gazprombank.ru",
    "www.gazprombank.ru",
    "..."
  ],
  "root_certs": [
    "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"
  ]
}

The JSON structure contains two values, with keys root_certs and host_masks. The two values respectively contain a list of PEM-encoded root certificates and a list of DNS names for which these root certificates are allowed to be used to make trust decisions. The list of ‘host masks’ contains DNS names of organizations for which a certificate has been issued.

The list of names in the host_masks field is a subset of the “List of domains for which security certificates have been issued” as published on the TLS page of Gosuslugi public services portal. This list can be seen as a low-tech, non-verifiable log of all certificates that have been issued thus far. It is used by Yandex Browser as an allowlist of host names for which the Russian Trusted Root CA can be used to make trust decisions.

What I found a bit concerning is that Yandex has built this infrastructure where they can remotely add additional custom root certificates to a user’s browser. In theory, this could be used to deliver a custom root certificate to a subset of the users in a transparent and very targeted fashion. For example, based on IP address or the unique client identifier included in the HTTP request. Which, in turn, could be abused to decrypt their HTTPS communications.

Russian Trusted Root CA

At the moment, the root_certs field contains a single PEM-encoded RSA root certificate of the Russian Trusted Root CA. This is the same certificate as the "CA Root Certificate" published on the Gosuslugi portal.

image

Russian CA hierarchy

Russia’s national certificate authority has a simple structure. At the top of the certificate hierarchy is the Russian Trusted Root CA. Issued leaf certificates ultimately chain up to this root CA. Between the root CA and the leaf certificates, there is the subordinate CA that is used for both certificate signing and certificate revocation list (CRL) signing.

To obtain a certificate and have it trusted by the supported browsers, you have to submit a request to the Ministry of Digital Development. This request is said to be reviewed within five business days. If approved, the certificate is issued and the DNS names on the certificate are added to a public list. Yandex adds the newly added DNS names to their ‘custom root certificates’ remote configuration file. As soon as all Yandex Browser clients have picked up the configuration changes, the new certificate works.

The Russian government is operating a very bare-bones certificate authority. It does not conform to the Baseline Requirements or the policies of the public root programs. Just based on a cursory review of the certificates issued so far, I already identified a number of issues. Certificate serial numbers are sequential, not random, and do not have the minimum 64 bits of entropy. Issued certificates are not published to a certificate transparency log (Update: Certificate Transparency is now supported. See update at the bottom.), which makes it impossible to independently audit them and detect potential issues like mis-issuance. There are other issues that show not all inputs are validated properly, which may indicate that certificate issuance is a semi-manual process. For example, there is one certificate where the Common Name is not included in the ‘Subject Alternative Names’ field. I don’t know if they intend to take the necessary steps to become a publicly trusted certificate authority. If they do, they would have a long road ahead of them.

There were some suggestions that the purpose of this new certificate authority is to allow the Russian government to intercept and decrypt all HTTPS communications. This is what the Kazakh government has been attempting to do since 2015 by asking citizens to install a special root certificate. There are no indications that this is the case in Russia. Their certificate authority operates more like a normal certificate authority, in the sense that it only issues certificates for DNS names for which the ownership could be verified. Furthermore, browsers like Yandex have implemented technical controls to prevent this certificate authority from being used for DNS names that are not on the allowlist.

This is not to say that the infrastructure could not be repurposed to decrypt intercepted HTTPS communications, but the purpose appears to be to support Russian organizations that may soon be unable to find a certificate authority to issue them publicly trusted certificates.

For anyone interested, I have added all files referenced in this post to a public GitHub repository, including all certificates that are currently being used in the wild.

Update (May 3, 2022)

Yandex reached out to me to share that they have added support for Certificate Transparency to Yandex Browser, requiring all new certificates to be logged to a Certificate Transparency log. New certificates are logged to three separate Certificate Transparency logs operated by Yandex, VK, and the Russian government (JSON-based log list). A signed certificate timestamp (SCT) is attached to the certificates. Yandex is planning to freeze updates to the allowlist once users have upgraded to the latest version of Yandex Browser with Certificate Transparency support for the Russian Trusted Root CA. The allowlist will be fully removed after all certificates without an embedded SCT have expired. This is a step in the right direction to make this certificate authority publicly accountable. I have not reviewed the implementation yet.

If you can, please consider making a donation to the Come Back Alive Foundation (and ask your employer to match your gift) to help save Ukraine and Ukrainians. Slava Ukraini!