diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 0000000..6a13cc1 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,42 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python application + +on: + push: + tags: + - 'v*' + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-22.04 + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + python3 schema_creator.py + python3 database_filler.py + - name: release + uses: ncipollo/release-action@v1 + with: + artifacts: "requirements.db" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26cfd53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*/__pycache__/ +output.prisma +requirements.db +.env/ \ No newline at end of file diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 0000000..691e16f --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,25 @@ +This file lists the main contributions. For the full list of contributions, please refer to the commit log. + +* Alessandro Tomasi ([@wry-run](https://www.github.com/wry-run)) + - initial data extraction and structuring from + - ANSSI - Recommandations de sécurité relatives à TLS `v1.2` + - BSI - `TR-02102-2` and `TR-03116-4` + - NIST - `SP 800-52 Rev. 2` + +* Salvatore Manfredi ([@NetBender](https://www.github.com/NetBender)) + - initial data review, formatting and translation + - data extraction from + - AgID - `AgID-RACCSECTLS-01` + - Mozilla - Recommended configurations `v5.6` + - NIST - `SP 800-131A Rev. 2` + +* Riccardo Germenia ([@Odinmylord](https://www.github.com/Odinmylord)) + - data review, format standardization + - addition of contextual notes to store references and reasonings + - data extraction from + - Mozilla - Recommended configurations `v5.7` + - NIST - `SP 800-131A Rev. 2` and `SP 800-186` + - dataset structuring + - database schema definition (Prisma) + - reproducible scheme generation + - reproducible SQLite database generation diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..da6ab6c --- /dev/null +++ b/LICENSE @@ -0,0 +1,396 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee93a34 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# TLS Compliance Dataset +[![License: CC BY 4.0](https://img.shields.io/badge/License-CC_BY_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by/4.0/) + +The content of this repository is the result of the gathering, translation, standardization and structuring of a set of technical requirements extracted from five cybersecurity agencies' guidelines. + +The examined guidelines are: +- **AgID** [AgID-RACCSECTLS-01](https://cert-agid.gov.it/wp-content/uploads/2020/11/AgID-RACCSECTLS-01.pdf) +- **ANSSI** [v1.2](https://cyber.gouv.fr/sites/default/files/2017/07/anssi-guide-recommandations_de_securite_relatives_a_tls-v1.2.pdf) +- **BSI** [TR-02102-2](https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TG02102/BSI-TR-02102-2.html) and [TR-03116-4](https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR03116/BSI-TR-03116-4.html) +- **Mozilla** [v5.7](https://wiki.mozilla.org/Security/Server_Side_TLS) +- **NIST** [SP 800-52 Rev. 2](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-52r2.pdf) (and related documents) + + +The result of this process is a dataset that can be audited, inspected and peer reviewed. + +#### Glossary +- Configurable element - each element whose availability can be set by the system administrator (e.g., specific protocol versions); +- Guideline - a document issued by a national cybersecurity agency that contains technical requirement for various configurable elements; +- Level - the requirement level that every guideline assigns to each configurable element; +- Profile - a use case defined by a guideline (e.g., customer-facing and government-facing service); +- Variant - subset of elements that can have alternative configurations levels (e.g., prioritization of ephemeral keys use); +- Condition - an additional requirement that restricts the use of a configurable element (e.g., "use *element* up to year 2030"). + +## Dataset Structure +The dataset is composed of multiple `.md` files that are used to store different sets of configurable elements. Each file contains a table with the following structure: +| Configurable Element | (Guideline1, Profile1) | (Guideline1, Profile1) | ... | (Guidelinen, Profilen) | (Guidelinen, Profilen) | +| -------------------- | --------------------- | ----------------------- | --- | --------------------- | ----------------------- | +| Element1 | Level1,1 | Condition1,1 | ... | Level1,n | Condition1,n | +| Element2 | Level2,1 | Condition2,1 | ... | Level2,n | Condition2,n | +| ... | ... | ... | ... | ... | ... | +| Elementn | Leveln,1 | Conditionn,1 | ... | Leveln,n | Conditionn,n | + + +#### Additional Information +For additional information on how to add a new guideline or a new table to the dataset, please refer to the [Standard Compliance Module](). + +### Configurable Elements + +Each file lists the requirements level of + +- Certificates-related + - [Certificate.md](): common fields; + - [Certificate Extensions.md](): specific extensions; + - [Certificate Signature.md](): algorithms that can be used to sign a certificate; +- [Cipher Suites.md](): cipher suites; +- [Hash Algorithms.md](): the hash algorithms that can be used together with the respective [signatures](); +- [Key Lengths.md](): the key lengths that can be used for both key exchange and signature algorithms; +- [Misc.md](): other configurable elements that do not fall into a specific category (e.g., vulnerability-specific mitigations); +- [Protocol.md](): SSL and TLS versions; +- [Signature Algorithms.md](): the signature algorithms that can be used for forward secrecy; +- [TLS Extensions.md](): the TLS extensions that can be used during a secure transmission. + +## Reproducibility +To enable reproducibility of the dataset, the repository also contains a set of scripts that can be used to generate a SQLite database that maps the dataset. + +- `schema_creator.py`: reads the dataset and by using [Prisma Client Python](https://prisma-client-py.readthedocs.io/en/stable/) creates an empty SQLite database with the tables needed to store the dataset. The database will be stored in a file called `requirements.db` (in the root directory of the repository); +- `database_filler.py`: reads the dataset and fills all the tables of `requirements.db` with the data contained in the dataset. + +## How to contribute +Please refer to the [Wiki](https://github.com/stfbk/tls-compliance-dataset/wiki) page. + + +## Related Projects + +This dataset is the result of a study aimed to design a methodology to assess the compliance level of new and existing webservers. More detail about the methodology and the process behind its creation can be found in the paper *Automating Compliance for Improving TLS Security Postures: An Assessment of Public Administration Endpoints*. + + + +The content of this dataset is an integral part of [TLSAssistant](https://github.com/stfbk/tlsassistant), an open-source modular framework capable of identifying a wide range of TLS vulnerabilities and assessing compliance with multiple guidelines. Its actionable report can assist the user in correctly and easily fixing their configurations. diff --git a/database_filler.py b/database_filler.py new file mode 100755 index 0000000..6efbdff --- /dev/null +++ b/database_filler.py @@ -0,0 +1,316 @@ +import sqlite3 +from copy import deepcopy +from typing import Tuple + +import pandas as pd + +from utils.configs import sheets_mapping, different_names_pos, sheet_columns, guidelines, converters +from utils.filler_utils import get_requirements_columns, get_columns_count_for_guideline, split_sheet, \ + get_version_name_for_database, get_guideline_name_for_database, is_double_guideline, get_first_col_for_guideline, \ + get_column, read_dataframes + +dataframe = read_dataframes({"converters":converters, "dtype":str}) +for df in dataframe: + dataframe[df] = dataframe[df].applymap(lambda x: x.strip() if isinstance(x, str) else x) + +sheet_with_extra_table = { + "TLS extensions": ("applies to version", "TlsVersionExtension") +} + +conn = sqlite3.connect("requirements.db") +cur = conn.cursor() + + +def prepare_database(): + cur.execute("SELECT name FROM sqlite_master WHERE type='table'") + for table in cur.fetchall(): + cur.execute("DELETE FROM " + table[0]) + conn.commit() + + +def insert_guideline_info(): + cur.executemany("INSERT OR REPLACE INTO Guideline VALUES (?, ?)", + [(guideline, guidelines[guideline]) for guideline in guidelines]) + + +def get_cell_for_df(df: pd.DataFrame, row_index: int, header): + col_index = 0 + for col_index, col in enumerate(df.columns): + if col[0] == header[0]: + break + return df.iloc[row_index: row_index + 1, col_index:col_index + 1].iat[0, 0] + + +def get_name_from_index_for_sheet(index, sheet_name: str) -> str: + """ + Gets the name of the item for that row. Some sheets have the name column in a different position, for that case + see the different_names_pos dictionary + :param index: row index + :param sheet_name: sheet in which the search should be done + :return: item_name: the name for the row at index in the sheet + """ + column = different_names_pos.get(sheet_name, (0, 1))[0] + return dataframe[sheet_name].iloc[index:index + 1, column:column + 1].iat[0, 0] + + +def get_additional_info(index, sheet_name: str): + column, lengths = different_names_pos.get(sheet_name, (0, 1)) + return_vals = [] + tmp_df = dataframe[sheet_name].iloc[index:index + 1, column:column + lengths] + if lengths > 1: + for i in range(1, lengths): + val = tmp_df.iat[0, i] + return_vals.append(val) + return return_vals + + +def already_parsed(col_name: str) -> bool: + for _, c2 in sheet_with_extra_table.items(): + if c2[0] == col_name.strip(): + return True + return False + + +def values_to_add(r: pd.Series, columns: pd.Index) -> Tuple: + """Given a series of values checks if those values belong to columns that were already parsed + :param r The row (Series) containing the values that need to be checked + :param columns: The columns of the dataframe from which the row is taken + """ + val_list = r.to_list() + i = 0 + for c in columns: + if already_parsed(c[0]): + val_list.pop(i) + else: + i += 1 + return tuple(val_list) + + +def has_extra_table(sheet_name: str) -> Tuple: + return sheet_with_extra_table.get(sheet_name, ()) + + +def fill_extra_table(sheet_name: str) -> bool: + """ + This function takes the name of a sheet as a param, uses it to get the column names from which it should get data + and the table in which to insert the data using the sheet_with_extra_table dictionary and then adds this data to the + database. + + :param sheet_name: the sheet that has an extra table + :return: False if the sheet doesn't have an extra table, True if it committed to the database + """ + column, table = sheet_with_extra_table.get(sheet_name, (None, None)) + if not column or not table: + return False + file_sheet: pd.DataFrame = dataframe[sheet_name] + # The first column is almost always the names column + names: pd.Series = get_column(file_sheet, 0) + # Get only the columns that must be inserted in the extra table + versions = file_sheet.filter(like=column) + versions_names = {} + insertion_query = f"INSERT OR REPLACE INTO {table} VALUES (?, ?)" + values_to_insert = [] + # prepare the mapping from index to column + for pos, version in enumerate(versions.columns.to_list()): + versions_names[pos] = version[1] + + for pos, content in versions.iterrows(): + name = names[pos] + # This variable i is used to cycle through the column's name without having to add it to the dataframe + # It can probably be avoided by using the join in pandas, but I can't get it to work + i = 0 + for c in content: + if pd.notna(c): + values_to_insert.append( + (versions_names[i % len(versions.columns)], name)) + i += 1 + cur.executemany(insertion_query, values_to_insert) + conn.commit() + return True + + +if __name__ == "__main__": + prepare_database() + insert_guideline_info() + guidelines_mapping = {} + for guideline in guidelines: + guidelines_mapping[guideline.upper()] = guideline + for sheet in dataframe: + sheet_mapped = sheets_mapping.get(sheet.strip()) + if isinstance(sheet, str) and sheet_mapped: + done = False + values = [] + if has_extra_table(sheet): + fill_extra_table(sheet) + general_dataframe, guidelines_dataframe = split_sheet(dataframe[sheet]) + values_tuple = () + # old_values is needed for some strange cases like key_signature + old_values = [] + for row in general_dataframe.iterrows(): + # row[0] is the index, row[1] is the actual content of the line + values_tuple = values_to_add(row[1], general_dataframe.columns) + if not len(old_values): + old_values = [v for v in values_tuple] + else: + tmp_list = [] + for i, v in enumerate(values_tuple): + if pd.isna(v) and v != old_values[i]: + tmp_list.append(old_values[i]) + else: + tmp_list.append(v) + values_tuple = tuple(tmp_list) + old_values = tmp_list + if values_tuple[0] != "Certificate Type": + values.append(values_tuple) + values_string = "(" + values_string += "?," * len(values_tuple) + # Remove last ',' and replace it with ')' + values_string = values_string[:-1] + ")" + sql_query = f"INSERT OR REPLACE INTO {sheet_mapped} VALUES " + values_string + cur.executemany(sql_query, values) + conn.commit() + values = [] + + # Start of guideline specific part + requirements_columns = get_requirements_columns(guidelines_dataframe, sheet) + guidelines_columns_count = get_columns_count_for_guideline(guidelines_dataframe) + + values_dict = {} + last_item = "" + + # maybe this whole part can be rewritten using iloc + old_name = "" + for row in guidelines_dataframe.iterrows(): + row_dictionary = row[1].to_dict() + for header in row_dictionary: + # header[0] is guideline_name + item_name = get_name_from_index_for_sheet(row[0], sheet) + old_name = item_name + guideline = get_guideline_name_for_database(header[0]) + version_name = get_version_name_for_database(header[1]) + table_name = sheet_mapped + guideline + version_name + content = row_dictionary[header] + if header[1] in requirements_columns[header[0]]: + # This is the case for sheets like cipher suite + if sheet_columns.get(sheet, {}).get(header[0]): + level_column = get_first_col_for_guideline(guidelines_dataframe, guideline) + level = get_cell_for_df(guidelines_dataframe, row[0], (guideline, level_column)) + # If the cell is empty and the level isn’t negative (must not, not recommended) + # then "must not" is used as the level. + if level == "": + content = level + if pd.notna(content) or level in ["not recommended", "must not"]: + if content not in ["recommended", "must"]: + content = level + else: + content = "must not" + + # this block is to prepare the dictionary + if not values_dict.get(table_name): + values_dict[table_name] = {row[0]: []} + if not values_dict[table_name].get(row[0]): + values_dict[table_name][row[0]] = [] + # end of the block + + # Vertically merged cells contain the value only in the first cell + if pd.isna(item_name) and not pd.isna(content): + item_name = values_dict[table_name][row[0] - 1][0] + + # First the guideline name is added + values_dict[table_name][row[0]].append(guidelines_mapping.get(guideline, guideline)) + + # Then the name of the row is added + values_dict[table_name][row[0]].append(item_name) + # If this table needs extra data it gets added here + for el in get_additional_info(row[0], sheet): + values_dict[table_name][row[0]].append(el) + + values_dict[table_name][row[0]].append(content) + + elif pd.notna(header[1]) and \ + get_first_col_for_guideline(guidelines_dataframe, header[0]) != header[1]: + # update all the lists of the same guideline with the condition + columns_to_apply = [] + if " [" in header[1]: + columns_to_apply = header[1].split(" [")[1].replace("]", "").split(",") + columns_to_apply = [int(c.strip()) for c in columns_to_apply] + counter = 0 + for t_name in values_dict: + guideline_db_name = get_guideline_name_for_database(header[0]) + # this is needed only for the case of KeyLengthsBSI and KeyLengths BSI (from ...) + has_valid_underscore = "_" in guideline_db_name and "_" in t_name + if t_name.startswith(sheet_mapped + guideline_db_name): + if "_" not in t_name or has_valid_underscore: + counter += 1 + if " [" in header[1] and counter not in columns_to_apply: + continue + values_dict[t_name][row[0]].append(content) + if is_double_guideline(header[0]): + tokens = header[0].split("+") + base_guideline = tokens[0].replace("(", "").strip() + for other_guideline in tokens[1:]: + other_name = get_guideline_name_for_database(other_guideline) + other_table = sheet_mapped + other_name + version_name + values_dict[other_table] = deepcopy(values_dict[table_name]) + for el in values_dict[other_table]: + # Update the guideline name + for i, entry in enumerate(values_dict[other_table][el]): + if isinstance(entry, str) and entry.upper() == base_guideline.upper(): + values_dict[other_table][el][i] = other_name + + # Convert all the data into tuples to add them to the database and group them by guideline name + values_groups = {} + for table in values_dict: + # Get the number of columns for the actual table + table_columns_count = len(cur.execute(f"PRAGMA table_info({table})").fetchall()) + entries = values_dict[table] + + # # This is to prevent the "this or X" condition to appear in tables that don't need it + # # this condition checks if the guideline has multiple versions for this sheet + # if table.startswith("Protocol") and table[len("Protocol"):] not in [g.upper() for g in guidelines]: + # for entry in entries: + # entry = entries[entry] + # # Since the problem is a condition, and it only verifies if there are four elements. + # # Last element is the condition + # # Second to last is the level + # print(entry) + # if len(entry) > 3 and pd.notna(entry[-1]): + # if entry[-2][-1] != "°": + # entry[-1] = None + last_level = None + + # This is to prevent the "this or X" condition to appear in tables that don't need it, only works + # for the case of Protocol sheet and only if the conditions are in adjacent lines + if table.startswith("Protocol"): + for index, entry in entries.items(): + # skip first element + if index == 0: + continue + if len(entry) > 3 and pd.notna(entry[-1]) and pd.notna(entries[index - 1][-1]): + if entry[-2] != entries[index - 1][-2]: + entry[-1] = None + entries[index - 1][-1] = None + + if not values_groups.get(table): + values_groups[table] = [] + for index in entries: + entry = entries[index] + if pd.notna(entry[1]) and entry[1] != "Certificate Type" and entry[1] != "NIST": + # The double check is needed because of the case Mozilla + AGID which share the same pointer to + # the list of values + if len(entry) < table_columns_count: + entry.insert(0, index) + # Every remaining column is filled with None + while len(entry) < table_columns_count: + entry.append(None) + values_groups[table].append(tuple(entry)) + for table in values_groups: + values = values_groups[table] + values_string = "(" + # The values list should contain tuples that are all the same size + values_string += "?," * (len(values[0])) + # Remove last ',' and replace it with ')' + values_string = values_string[:-1] + ")" + sql_query = f"INSERT OR REPLACE INTO {table} VALUES " + values_string + cur.executemany(sql_query, values) + conn.commit() diff --git a/markdown/Certificate Extensions.md b/markdown/Certificate Extensions.md new file mode 100644 index 0000000..ce0ac16 --- /dev/null +++ b/markdown/Certificate Extensions.md @@ -0,0 +1,67 @@ + | Extension | ('NIST', '') | ('NIST', 'critical') [^2] | ('NIST', 'condition') | ('BSI', '') [^1] | ('BSI', 'critical') | ('BSI', 'condition') | ('ANSSI', '') | ('ANSSI', 'condition') | ('MOZILLA', '') | + | :------------------------------- | :---------------- | :------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------- | :------------------ | :---------------------------------------------------------------------------------------------------------------------- | :-------------------- | :--------------------------------------------------------- | :---------------- | + | authorityKeyIdentifier | recommended | | CHECK_AKI [^3] | \ | | | must [^4] | | \ | + | subjectKeyIdentifier [^5] | recommended | | NOTE_ALWAYS The guidelines state `Same as in Public-Key Cryptography Standards [PKCS 10] request or calculated by the issuing CA`. The tool can not verify this condition since this specific check can only be performed by monitoring the endpoint during the certificate issuing phase [^6] | \ | | | | | \ | + | keyUsage [^7] | recommended | yes | (VALUE CertificateExtensions Digital Signature in keyUsage OR VALUE CertificateExtensions Key Agreement in keyUsage) and NOTE_FALSE Invalid keyUsage, allowed key usages are digital signature if using RSA certificate and key agreement if using ECDH or DH certificate [^8] | must | yes | | must [^9] | | \ | + | extendedKeyUsage [^10] | must [^11] | | NOTE_FALSE Issue detected: {reason} within certificate #{cert} AND VALUE CertificateExtensions TLS Web Server Authentication in extendedKeyUsage [^12] | recommended | | | must [^13] | | \ | + | extendedKeyUsage [^14] | must not | | (NOTE_TRUE Issue detected: {reason} within certificate #{cert} AND VALUE CertificateExtensions Any Extended Key Usage in extendedKeyUsage) OR CHECK_SAME_KEYUSAGE [^15] | \ | | | | | \ | + | Certificate Policies | optional | | | \ | | | \ | | \ | + | subjectAltName [^16] | must [^17] | | VALUE CertificateExtensions DNS in subjectAltName OR VALUE CertificateExtensions IP Address in subjectAltName [^18] | must not | | NOTE_TRUE Issue detected: {reason} within certificate #{cert} and VALUE CertificateExtensions * in subjectAltName [^19] | must [^20] | | \ | + | authorityInfoAccess [^21] | must [^22] | | VALUE CertificateExtensions OCSP - URI in authorityInfoAccess and NOTE_FALSE the authorityInfoAccess extension must have a field CA Issuers containing HTTP URL for certificates issued to issuing CA [^23] | must | | THIS or CertificateExtensions CRL Distribution Points | must | THIS or CertificateExtensions CRL Distribution Points | \ | + | authorityInfoAccess | must [^24] | | VALUE CertificateExtensions CA ISSUERS - URI in authorityInfoAccess and NOTE_FALSE the authorityInfoAccess extension must have the Online Certificate Status Protocol and it must contain HTTP URL for the issuing CA OCSP responder [^25] | | | | | | \ | + | crlDistributionPoints [^26] | optional | | VALUE CertificateExtensions IP in crlDistributionPoints OR VALUE CertificateExtensions URI in crlDistributionPoints [^27] | must | | THIS or CertificateExtensions Authority Information Access | must | THIS or CertificateExtensions Authority Information Access | \ | + | crlDistributionPoints | must not | | NOTE_TRUE Issue detected: {reason} within certificate #{cert} AND (VALUE CertificateExtensions Relative Name in crlDistributionPoints OR VALUE CertificateExtensions CRL Issuer in crlDistributionPoints OR VALUE CertificateExtensions Reasons in crlDistributionPoints) AND DISABLE_IF False [^28] | | | | | | \ | + | ct_precert_scts [^29] | optional [^30] | | | | | | \ | | \ | + | OCSP must staple extension [^31] | optional [^32] | | | | | | \ | | \ | + +[^1]: BSI TR-03116-4 +[^2]: Each extension in a certificate is designated as either critical or non-critical. A certificate-using system MUST reject the certificate if it encounters a critical extension it does not recognize or a critical extension that contains information that it cannot process. A non-critical extension MAY be ignored if it is not recognized, but MUST be processed if it is recognized. The following sections present recommended extensions used within Internet certificates and stand + + https://www.rfc-editor.org/rfc/rfc5280 section 4.2 +[^3]: Same as subject key identifier in issuing CA certificate; Prohibited: Issuer DN, Serial Number tuple +[^4]: R32 +[^5]: Subject Key Identifier (SKI) +[^6]: Same as in Public-Key Cryptography Standards (PKCS) 10 request or calculated by the issuing CA +[^7]: Key Usage +[^8]: RSA, ECDSA, or DSA signature certificate: digital signature; + ECDH or DH certificate: key agreement +[^9]: R27 +[^10]: Extended Key Usage +[^11]: server +[^12]: id-kp-serverAuth {1 3 6 1 5 5 7 3 1} + http://oid-info.com/get/1.3.6.1.5.5.7.3.1 +[^13]: R28 +[^14]: Extended Key Usage +[^15]: the keyAgreement and keyEncipherments are considered mutually exclusive as show in section 5.4.3 of https://www.etsi.org/deliver/etsi_ts/102200_102299/102280/01.01.01_60/ts_102280v010101p.pdf +[^16]: Subject Alternative Name (SAN) +[^17]: Required. Multiple SANs are permitted, e.g., for load balanced environments. +[^18]: DNS host name, or IP address if there is no DNS name assigned. Other name forms may be included, if appropriate. +[^19]: use wildcards in CN +[^20]: R29 +[^21]: Authority Information Access +[^22]: Required. Multiple SANs are permitted, e.g., for load balanced environments. +[^23]: field id-ad-caIssuers +[^24]: Required. Multiple SANs are permitted, e.g., for load balanced environments. +[^25]: field id-ad-caIssuers +[^26]: CRL Distribution Points +[^27]: HTTP value in distributionPoint + field pointing to a full and complete CRL + + We don't check if the CRL is full and complete. We only check if the value in the cert is of type IP or URI +[^28]: A CRL is indicated by a DistributionPoint ::= SEQUENCE. + This SEQUENCE can contain three items: + distributionPoint: DistributionPointName + reasons: ReasonFlags + cRLIssuer: GeneralNames. + + The DistributionPointName type is a CHOICE with two options: + fullName + nameRelativeToCRLIssuer + + A valid distributionPoint must not have the "reasons" and "cRLIssuer" fields and the distributionPoint can not be of type nameRelativeToCRLIssuer +[^29]: Signed Certificate Timestamps List +[^30]: Optional. This extension contains a sequence of Signed Certificate + Timestamps, which provide + evidence that the certificate has been submitted to Certificate Transparency logs. +[^31]: TLS Certificate Status Request +[^32]: Optional. This extension (sometimes referred to as the “must staple” extension) may be present to indicate to clients that the server supports OCSP stapling and will provide a stapled OCSP response when one is requested. diff --git a/markdown/Certificate Signature.md b/markdown/Certificate Signature.md new file mode 100644 index 0000000..00168ac --- /dev/null +++ b/markdown/Certificate Signature.md @@ -0,0 +1,20 @@ + | Certificate signature algorithm | IANA | TLS version | ('NIST', '') [^1] | ('NIST', 'Condition') | ('BSI', '') [^2] | ('BSI', 'Condition') [^5] | ('ANSSI', '') [^3] | ('MOZILLA (+AgID)', 'Modern') [^4] | ('MOZILLA (+AgID)', 'Intermediate') | ('MOZILLA (+AgID)', 'Old') | + | :----------------------------------- | ---: | ----------: | :------------------- | :--------------------------------------------------------------- | :------------------- | :------------------------------------------------------- | :------------------- | :--------------------------------- | :---------------------------------- | :------------------------- | + | anonymous | 0 | 1.2 | must not [^6] | | \ | | must not [^7] | \ | \ | \ | + | rsa [^8] | 1 | 1.2 | must | THIS or CertificateSignature ecdsa and CHECK_KEY_TYPE rsa [^9] | recommended | THIS or CertificateSignature dsa;ecdsa AND YEAR 2025 | optional | \ | \ | \ | + | dsa | 2 | 1.2 | \ | CHECK_KEY_TYPE dsa [^10] | recommended | THIS or CertificateSignature rsa;ecdsa AND YEAR 2029 | \ | \ | \ | \ | + | ecdsa | 3 | 1.2 | must | THIS or CertificateSignature rsa and CHECK_KEY_TYPE ecddsa [^11] | recommended | THIS or CertificateSignature rsa;dsa | recommended | \ | \ | \ | + +[^1]: SP800-52 section 3.2 +[^2]: BSI-TR-02102-2, 3.3.3 + 3.4.3 +[^3]: R8 +[^4]: Being a list of recommendations: + + not mentioned --> not recommended +[^5]: Not explicitally mentioned but required to match the mechanical check of the conditions with the NIST case +[^6]: TLS servers conforming to this specification shall be configured with an RSA signature certificate or an ECDSA signature certificate +[^7]: R8+R5 +[^8]: We consider RSASSA-PSS as a subset of RSA (as stated in ANSSI v1.2 R8) +[^9]: At a minimum, TLS servers conforming to this specification shall be configured with an RSA signature certificate or an ECDSA signature certificate. +[^10]: recommended "if key is DH" +[^11]: At a minimum, TLS servers conforming to this specification shall be configured with an RSA signature certificate or an ECDSA signature certificate. diff --git a/markdown/Certificate.md b/markdown/Certificate.md new file mode 100644 index 0000000..c5c41d7 --- /dev/null +++ b/markdown/Certificate.md @@ -0,0 +1,6 @@ +| Certificate | ('NIST', '') | ('NIST', 'condition') | ('BSI', '') | ('BSI', 'condition') | ('ANSSI', '') | ('ANSSI', 'condition') | ('MOZILLA', '') | +| :------------------------- | :----------- | :----------------------------------------------------------------------------------------------------------------------------- | :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------- | ---------------------: | :---------------- | +| X.509 version | must | VALUE Certificate 2 == X.509 version and NOTE_FALSE In order for the certificate to be compliant it has to use X.509 version 2 | \ | | must | | \ | +| Issuer Distinguished Name | recommended | CHECK_DN Issuer Distinguished Name - der | must not | NOTE_TRUE BSI guidelines prohibit the usage of * in this field. Issue detected: {reason} within certificate #{cert} and VALUE Certificate * in [Issuer Distinguished Name][CN] | \ | | \ | +| validity | recommended | YEARS <= 3 and NOTE_FALSE In order for the certificate to be compliant it should have a validity of 3 years or less | must | YEARS <= 3 and NOTE_FALSE In order for the certificate to be compliant it must have a validity of 3 years or less | \ | | \ | +| Subject Distinguished Name | recommended | CHECK_DN Subject Distinguished Name - der | must not | NOTE_TRUE BSI guidelines prohibit the usage of * in this field. Issue detected: {reason} within certificate #{cert} and VALUE Certificate * in [Subject Distinguished Name][CN] | \ | | \ | diff --git a/markdown/Cipher Suites.md b/markdown/Cipher Suites.md new file mode 100644 index 0000000..62537d0 --- /dev/null +++ b/markdown/Cipher Suites.md @@ -0,0 +1,188 @@ +| MYSQL | IANA | ('NIST', 'Requirement') | ('NIST', 'Preferred #1') | ('NIST', 'Preferred #2') [^1] | ('NIST', 'Preferred #3') [^5] | ('NIST', 'Condition') [^6] | ('BSI', 'Requirement') [^7] | ('BSI', 'Preferred #1') | ('BSI', 'Preferred #2') [^2] | ('BSI', 'Federal req.') [^8] | ('BSI', 'Condition [3]') [^9] | ('ANSSI', '') [^10] | ('MOZILLA (+AgID)', 'Modern') [^11] | ('MOZILLA (+AgID)', 'Intermediate') [^3] | ('MOZILLA (+AgID)', 'Old') [^4] | +| --------------------------------------------------- | :--------- | :---------------------- | :----------------------- | :----------------------------- | :---------------------------- | :-------------------------------------------- | :-------------------------- | :---------------------- | :--------------------------- | :---------------------------- | :---------------------------------------------------------- | :--------------------- | :---------------------------------- | :--------------------------------------- | :------------------------------ | +| TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 | 0xC0,0x2B | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | must | THIS or CIPHER TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | recommended | \ | recommended | recommended | +| TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 | 0xC0,0x2C | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | recommended | \ | recommended | recommended | +| TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 | 0xCC,0xA9 | must not | | | | | \ | | | | | recommended | \ | recommended | recommended | +| TLS_ECDHE_ECDSA_WITH_AES_128_CCM | 0xC0,0xAC | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_AES_256_CCM | 0xC0,0xAD | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 | 0xC0,0xAE | optional | ✓ | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 | 0xC0,0xAF | optional | ✓ | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | 0xC0,0x23 | optional | ✓ | | | | recommended | ✓ | | must | THIS or CIPHER TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 | not recommended | \ | \ | recommended | +| TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 | 0xC0,0x24 | optional | ✓ | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | recommended | +| TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA | 0xC0,0x09 | optional | ✓ | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA | 0xC0,0x0A | optional | ✓ | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | 0xC0,0x2F | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | must | THIS or CIPHER TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | recommended | \ | recommended | recommended | +| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | 0xC0,0x30 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | recommended | \ | recommended | recommended | +| TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 | 0xCC,0xA8 | must not | | | | | \ | | | | | recommended | \ | recommended | recommended | +| TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 | 0xCC,0xAA | must not | | | | | \ | | | | | not recommended | \ | recommended | recommended | +| TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 | 0x00,0x9E | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | not recommended | \ | recommended | recommended | +| TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 | 0x00,0x9F | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | not recommended | \ | recommended | recommended | +| TLS_DHE_RSA_WITH_AES_128_CCM | 0xC0,0x9E | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_AES_256_CCM | 0xC0,0x9F | optional | ✓ | ✓ | | | recommended | ✓ | | ✓ | | \ | \ | \ | \ | +| TLS_DHE_RSA_WITH_AES_128_CCM_8 | 0xC0,0xA2 | optional | ✓ | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_DHE_RSA_WITH_AES_256_CCM_8 | 0xC0,0xA3 | optional | ✓ | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | 0xC0,0x27 | optional | ✓ | | | | recommended | ✓ | | must | THIS or CIPHER TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | not recommended | \ | \ | recommended | +| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 | 0xC0,0x28 | optional | ✓ | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | recommended | +| TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 | 0x00,0x67 | optional | ✓ | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | recommended | +| TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 | 0x00,0x6B | optional | ✓ | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | recommended | +| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA | 0xC0,0x13 | optional | ✓ | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA | 0xC0,0x14 | optional | ✓ | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_DHE_RSA_WITH_AES_128_CBC_SHA | 0x00,0x33 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DHE_RSA_WITH_AES_256_CBC_SHA | 0x00,0x39 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 | 0x00,0xA2 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | \ | \ | \ | \ | +| TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 | 0x00,0xA3 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | \ | \ | \ | \ | +| TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 | 0x00,0x40 | optional | ✓ | | | | recommended | ✓ | | ✓ | | \ | \ | \ | \ | +| TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 | 0x00,0x6A | optional | ✓ | | | | recommended | ✓ | | ✓ | | \ | \ | \ | \ | +| TLS_DHE_DSS_WITH_AES_128_CBC_SHA | 0x00,0x32 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DHE_DSS_WITH_AES_256_CBC_SHA | 0x00,0x38 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DH_DSS_WITH_AES_128_GCM_SHA256 | 0x00,0xA4 | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_DSS_WITH_AES_256_GCM_SHA384 | 0x00,0xA5 | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_DSS_WITH_AES_128_CBC_SHA256 | 0x00,0x3E | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_DSS_WITH_AES_256_CBC_SHA256 | 0x00,0x68 | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_DSS_WITH_AES_128_CBC_SHA | 0x00,0x30 | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DH_DSS_WITH_AES_256_CBC_SHA | 0x00,0x36 | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DH_RSA_WITH_AES_128_GCM_SHA256 | 0x00,0xA0 | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_RSA_WITH_AES_256_GCM_SHA384 | 0x00,0xA1 | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_RSA_WITH_AES_128_CBC_SHA256 | 0x00,0x3F | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_RSA_WITH_AES_256_CBC_SHA256 | 0x00,0x69 | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_DH_RSA_WITH_AES_128_CBC_SHA | 0x00,0x31 | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DH_RSA_WITH_AES_256_CBC_SHA | 0x00,0x37 | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 | 0xC0,0x2D | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 | 0xC0,0x2E | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 | 0xC0,0x25 | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 | 0xC0,0x26 | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA | 0xC0,0x04 | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA | 0xC0,0x05 | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 | 0xC0,0x31 | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 | 0xC0,0x32 | optional | | ✓ | ✓ | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 | 0xC0,0x29 | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 | 0xC0,0x2A | optional | | | | | recommended | | ✓ | | | \ | \ | \ | \ | +| TLS_ECDH_RSA_WITH_AES_128_CBC_SHA | 0xC0,0x0E | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDH_RSA_WITH_AES_256_CBC_SHA | 0xC0,0x0F | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_AES_128_GCM_SHA256 [^12] | 0x13,0x01 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | ✓ | ✓ [^13] | | recommended [^14] | recommended | recommended | recommended | +| TLS_AES_256_GCM_SHA384 | 0x13,0x02 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | ✓ | ✓ | | recommended | recommended | recommended | recommended | +| TLS_CHACHA20_POLY1305_SHA256 | 0x13,0x03 | must not | | | | | \ | | | | | recommended | recommended | recommended | recommended | +| TLS_AES_128_CCM_SHA256 | 0x13,0x04 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | ✓ | ✓ | | recommended | \ | \ | \ | +| TLS_AES_128_CCM_8_SHA256 [^15] | 0x13,0x05 | optional | ✓ | ✓ | ✓ | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 | 0xC0,0x37 | optional | ✓ | | | | recommended | ✓ | | must | NOTE_DISABLED only required if PSK is used | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 | 0xC0,0x38 | optional | ✓ | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 | 0xD0,0x01 | must not | | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 | 0xD0,0x02 | must not | | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 | 0xD0,0x05 | must not | | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 | 0x00,0xB2 | optional | ✓ | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 | 0x00,0xB3 | optional | ✓ | | | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 | 0x00,0xAA | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 | 0x00,0xAB | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_128_CCM | 0xC0,0xA6 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_256_CCM | 0xC0,0xA7 | optional | ✓ | ✓ | ✓ | | recommended | ✓ | | ✓ | | not recommended | \ | \ | \ | +| TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 | 0x00,0xB6 | must not | | | | | recommended | | ✓ | must | NOTE_DISABLED only required if PSK is used | \ | \ | \ | \ | +| TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 | 0x00,0xB7 | must not | | | | | recommended | | ✓ | ✓ | | \ | \ | \ | \ | +| TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 | 0x00,0xAC | must not | | | | | recommended | | ✓ | ✓ | | \ | \ | \ | \ | +| TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 | 0x00,0xAD | must not | | | | | recommended | | ✓ | ✓ | | \ | \ | \ | \ | +| TLS_PSK_DHE_WITH_AES_128_CCM_8 | 0xC0, 0xAA | optional | ✓ | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_DHE_WITH_AES_256_CCM_8 | 0xC0, 0xAB | optional | ✓ | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_128_GCM_SHA256 | 0x00, 0xA8 | optional | | ✓ | ✓ | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_256_GCM_SHA384 | 0x00, 0xA9 | optional | | ✓ | ✓ | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_128_CCM | 0xC0, 0xA4 | optional | | ✓ | ✓ | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_256_CCM | 0xC0, 0xA5 | optional | | ✓ | ✓ | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_128_CCM_8 | 0xC0, 0xA8 | optional | | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_256_CCM_8 | 0xC0, 0xA9 | optional | | ✓ | | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_128_CBC_SHA256 | 0x00, 0xAE | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_256_CBC_SHA384 | 0x00, 0xAF | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA | 0xC0, 0x35 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA | 0xC0, 0x36 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_128_CBC_SHA | 0x00, 0x90 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_DHE_PSK_WITH_AES_256_CBC_SHA | 0x00, 0x91 | optional | ✓ | | | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_128_CBC_SHA | 0x00, 0x8C | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_PSK_WITH_AES_256_CBC_SHA | 0x00, 0x8D | optional | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_RSA_WITH_AES_128_CCM | xC0, x9C | not recommended | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_RSA_WITH_AES_256_CCM | xC0, x9D | not recommended | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_RSA_WITH_AES_128_CCM_8 | xC0, xA0 | not recommended | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_RSA_WITH_AES_256_CCM_8 | xC0, xA1 | not recommended | | | | | \ | | | | | \ | \ | \ | \ | +| TLS_RSA_WITH_AES_128_GCM_SHA256 | x00, x9C | not recommended | | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_RSA_WITH_AES_256_GCM_SHA384 | x00, x9D | not recommended | | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_RSA_WITH_AES_128_CBC_SHA256 | x00, 3C | not recommended | | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_RSA_WITH_AES_256_CBC_SHA256 | x00, 3D | not recommended | | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_RSA_WITH_AES_128_CBC_SHA | x00, x2F | not recommended | | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_RSA_WITH_AES_256_CBC_SHA | x00, x35 | not recommended | | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_RSA_WITH_3DES_EDE_CBC_SHA | 0x00, 0x0A | must not | | | | | \ | | | | | \ | \ | \ | recommended | +| TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 | 0xC0,0x72 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 | 0xC0,0x73 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 | 0xC0,0x76 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 | 0xC0,0x77 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 | 0xC0,0x7C | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 | 0xC0,0x7D | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 | 0xC0,0x86 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 | 0xC0,0x87 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 | 0xC0,0x8A | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 | 0xC0,0x8B | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 | 0xC0,0x5D | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 | 0xC0,0x5C | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 | 0xC0,0x61 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 | 0xC0,0x60 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 | 0xC0,0x53 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 | 0xC0,0x52 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 | 0xC0,0x49 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 | 0xC0,0x48 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 | 0xC0,0x4D | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 | 0xC0,0x4C | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 | 0xC0,0x45 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 | 0xC0,0x44 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 | 0x00, 0xBE | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 | 0x00, 0xC4 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 | 0xCCAD | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 | 0xC091 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 | 0xC090 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 | 0xC09B | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 | 0xC09A | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 | 0xC097 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 | 0xC096 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 | 0xC06D | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 | 0xC06C | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 | 0xC071 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 | 0xC070 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 | 0xC067 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 | 0xC066 | must not | | | | | \ | | | | | not recommended | \ | \ | \ | +| TLS_FALLBACK_SCSV | 0x56,0x00 | must | ✓ | ✓ [^16] | ✓ | TLS <= 1.2 AND ! TLS 1.3 AND VERIFY_SCSV | \ | | | | | \ | \ | \ | \ | + +[^1]: "All cipher suites not explicitly mentioned MUST NOT be used" + + 800-52r2, Section 3.3.1 + +[^2]: TR 02102-2 section 3.3.1 + +[^3]: Les recommandations de la présente section dressent une liste blanche des algorithmes et paramètres cryptographiques souhaitables : tout ce qui n’est pas recommandé est implicitement déconseillé. En particulier, l’usage de la fonction de chiffrement de flux RC4 et des fonctions de hachage MD5 et SHA-1 est à proscrire. + +[^4]: Being a list of recommendations: + + not mentioned --> not recommended + +[^5]: Prefer ephemeral keys over static keys + + prefer DHE over DH + prefer ECDHE over ECDH + +[^6]: Prefer GCM or CCM modes over CBC mode + +[^7]: Prefer CCM over CCM_8 + +[^8]: Recommended cipher suites for TLS 1.2 with Perfect Forward Secrecy (Table 1) + + Perfect Forward Secrecy is generally recommended (footnote 2, page 8) + +[^9]: Recommended cipher suites for TLS 1.2 without Perfect Forward Secrecy (Table 2) + +[^10]: must support at least one of + +[^11]: the [3] is needed to specify which column the conditions should be applied to + +[^12]: Start of TLS 1.3 cipher suites + +[^13]: Section 3.4.4 TR-02102-2 + +[^14]: Section 2.3.2 TR-03116-4 + +[^15]: End of TLS 1.3 cipher suites + +[^16]: if the server supports versions of TLS prior to TLS 1.2 and does not support TLS 1.3. + 3.4.2.1 Fallback Signaling Cipher Suite Value (SCSV) diff --git a/markdown/Hash Algorithm.md b/markdown/Hash Algorithm.md new file mode 100644 index 0000000..ac1dda0 --- /dev/null +++ b/markdown/Hash Algorithm.md @@ -0,0 +1,16 @@ + | HashAlgorithm | IANA | TLS version | ('NIST', '') [^1] | ('BSI', '') | ('ANSSI', '') [^2] | ('MOZILLA (+AgID)', 'Modern') | ('MOZILLA (+AgID)', 'Intermediate') | ('MOZILLA (+AgID)', 'Old') | + | :------------ | ---: | ----------: | :----------------------- | :---------------- | :-------------------- | :---------------------------- | :---------------------------------- | :------------------------- | + | none | 0 | 1.2 | must not | \ | must not | \ | \ | \ | + | md5 | 1 | 1.2 | must not | \ | must not | \ | \ | \ | + | sha1 | 2 | 1.2 | must not | \ | must not | \ | \ | \ | + | sha224 | 3 | 1.2 | must not | \ | must not | \ | \ | \ | + | sha256 | 4 | 1.2 | recommended | recommended | must | \ | \ | \ | + | sha384 | 5 | 1.2 | recommended | recommended | must | \ | \ | \ | + | sha512 | 6 | 1.2 | recommended | recommended | must | \ | \ | \ | + +[^1]: Partly deduced from + 3.2.1 Server Certificate Profile + together with supported groups + first row, table at page 11, SP800-52 +[^2]: ANSSI only allows the usage of SHA-2 family hash algorithms. + SHA-2 family is defined as (SHA-256, SHA-384, SHA-512) diff --git a/markdown/Key lengths.md b/markdown/Key lengths.md new file mode 100644 index 0000000..ca53819 --- /dev/null +++ b/markdown/Key lengths.md @@ -0,0 +1,84 @@ +| Use | Algorithms | Minimum key length (bits) | ('NIST', '') | ('NIST', 'Use up to year') | ('BSI', '') [^1] | ('BSI', 'Use up to year') | ('BSI (from 1/1/2024)', '') [^2] | ('BSI (from 1/1/2024)', 'Use up to year') | ('ANSSI', '') | ('ANSSI', 'Use up to year') | ('MOZILLA (+AGID)', 'Modern') [^3] | ('MOZILLA (+AGID)', 'Intermediate') | ('MOZILLA (+AGID)', 'Old') | +| ------------------------------------------------- | --------------- | ------------------------------ | --------------------- | -------------------------- | ---------------------------- | ------------------------------- | -------------------------------- | ----------------------------------------- | ----------------- | --------------------------- | ---------------------------------- | ----------------------------------- | -------------------------- | +| Signature keys for certificates and key agreement | ECDSA | 224 | recommended | YEAR 2030 | \ [^4] | | \ [^5] | | \ | | \ | \ | \ | +| | ECDSA | 256 | recommended | YEAR 2031+ | recommended | YEAR 2029+ | recommended | YEAR 2029+ | recommended | YEAR 2030 | \ | \ | \ | +| | EdDSA [^6] | -1 [^7] | \ | | \ | | \ | | \ | | \ | \ | \ | +| | DSA [^8] | 2048 | recommended [^9] | YEAR 2030 | must not [^10] | | must not [^11] | | \ | | \ | \ | \ | +| | DSA | 3076 | recommended [^12] | YEAR 2031+ | recommended [^13] | YEAR 2029+ | recommended [^14] | YEAR 2029+ | \ | | \ | \ | \ | +| | RSA | 2048 | recommended | YEAR 2030 | recommended | YEAR 2023 [^15] | must not [^16] | | recommended | YEAR 2030 | \ | recommended | \ | +| | RSA | 3076 | recommended | YEAR 2031+ | recommended | YEAR 2029+ | recommended [^17] | YEAR 2029+ | \ | | \ | \ | \ | +| | RSA | 1024 | \ | | \ | | \ | | \ | | \ | \ | recommended | +| Static and ephemeral Diffie-Hellman keys | ECDH | 224 | \ | | \ [^18] | | \ [^19] | | \ | | \ | \ | \ | +| | ECDH | 256 | \ | | recommended | YEAR 2029+ | recommended | YEAR 2029+ | \ | | \ | \ | \ | +| | DH | 1024 | \ | | \ | | \ | | \ | | \ | \ | recommended | +| | DH | 2048 | \ | | must not [^20] | | must not [^21] | | \ | | \ | recommended | \ | +| | DH | 3072 | \ | | recommended [^22] | YEAR 2029+ | recommended [^23] | YEAR 2029+ | \ | | \ | \ | \ | + +[^1]: TR-02102-2 section 3.6.1 +[^2]: TR-02102-2 section 3.6.1 + and + TR-02102-1, version 2023-1, Table 3.1 +[^3]: Being a list of recommendations: + + not mentioned --> not recommended +[^4]: Not mentioned starting from version 2023-01 of TR-02102-2 +[^5]: Not mentioned starting from version 2023-01 of TR-02102-2 +[^6]: not mentioned in any target guideline. + First mentioned in SP800-131 +[^7]: non specificato +[^8]: DSA is the algorithm, DSS is its standardization made by NIST + + Source: FIPS 186-5 +[^9]: NIST refers to DSA as DSS +[^10]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1 +[^11]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1 +[^12]: NIST refers to DSA as DSS +[^13]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1 + + + + This is translated as recommended since the must is limited to the context of the DSA keys +[^14]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1. + + + This is translated as recommended since the must is limited to the context of the DSA keys +[^15]: As an interim arrangement, the usage of RSA keys of length at least 2000 bits will however + remain compliant with this Technical Guideline through 2023. +[^16]: "Transitionally, also the use of RSA-keys with a length of ≥ 2000 bits will remain compliant until the end of 2023; from 2024 onwards, an RSA key length of ≥ 3000 bits will be mandatory." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1 +[^17]: "Transitionally, also the use of RSA-keys with a length of ≥ 2000 bits will remain compliant until the end of 2023; from 2024 onwards, an RSA key length of ≥ 3000 bits will be mandatory." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1. + + + + This is translated as recommended since the must is limited to the context of the RSA keys +[^18]: Not mentioned starting from version 2023-01 of TR-02102-2 +[^19]: Not mentioned starting from version 2023-01 of TR-02102-2 +[^20]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1 +[^21]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1 +[^22]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1 + + + This is translated as recommended since the must is limited to the context of the DH keys +[^23]: "A key length of ≥ 3000 bits will be mandatory from 2023 for cryptographic DLIES and DSA implementations that are to be compliant with this Technical Guideline." + + Change mandated by BSI-TR-02102-1, version 2023-1, Table 3.1. + + + This is translated as recommended since the must is limited to the context of the DH keys diff --git a/markdown/Misc.md b/markdown/Misc.md new file mode 100644 index 0000000..28cdf7f --- /dev/null +++ b/markdown/Misc.md @@ -0,0 +1,4 @@ + | Misc | ('NIST', '') | ('BSI', '') | ('ANSSI', '') | ('AgID', '') | + | :----------------------------- | :----------- | :-------------- | ------------: | :-------------- | + | Use TLS Compression | must not | not recommended | | not recommended | + | Client-initiated renegotiation | | | | not recommended | diff --git a/markdown/Protocols.md b/markdown/Protocols.md new file mode 100644 index 0000000..77b0544 --- /dev/null +++ b/markdown/Protocols.md @@ -0,0 +1,16 @@ + | Protocols | ('NIST', 'Government-only') | ('NIST', 'Customer-facing') | ('NIST (from 1/1/2024)', 'Government-only') | ('NIST (from 1/1/2024)', 'Customer-facing') | ('BSI', 'Federal applications') [^2] | ('BSI', 'Customer-facing') [^3] | ('BSI', 'Customer-facing conditions') | ('ANSSI', '') | ('AgID', '') | ('AgID', 'conditions') | ('MOZILLA', 'Modern') [^1] | ('MOZILLA', 'Intermediate') | ('MOZILLA', 'Old') | + | :-------- | :-------------------------- | :-------------------------- | :------------------------------------------ | :------------------------------------------ | :----------------------------------- | :------------------------------ | :------------------------------------ | :------------ | :---------------- | :------------------------ | :------------------------- | :-------------------------- | :----------------- | + | SSL 2.0 | must not | must not | must not | must not | must not | not recommended | | must not | \ | | \ | \ | \ | + | SSL 3.0 | must not | must not | must not | must not | must not | not recommended | | must not | \ | | \ | \ | \ | + | TLS 1.0 | must not | not recommended | must not | not recommended | must not | not recommended | | must not | not recommended | | \ | \ | recommended | + | TLS 1.1 | not recommended | not recommended | not recommended | not recommended | must not | not recommended | | must not | not recommended | | \ | \ | recommended | + | TLS 1.2 | must | must | not recommended | not recommended | must | recommended | THIS or PROTOCOLS TLS 1.3 | optional | must | THIS or PROTOCOLS TLS 1.3 | \ | recommended | recommended | + | TLS 1.3 | recommended | recommended | must | must | recommended | recommended | THIS or PROTOCOLS TLS 1.2 | recommended | must | THIS or PROTOCOLS TLS 1.2 | recommended | recommended | recommended | + +[^1]: "All protocols not explicitly mentioned MUST NOT be used" + + Policy inferred from +[^2]: Technische Richtlinie BSI TR-03116 + Kryptographische Vorgaben für Projekte der Bundesregierung Teil 4 – Kommunikationsverfahren in Anwendungen + Datum: 24.01.2022 +[^3]: TR-02102-2 Version 2022-01 Section 3.2 diff --git a/markdown/Signature algorithms.md b/markdown/Signature algorithms.md new file mode 100644 index 0000000..0ab0cb5 --- /dev/null +++ b/markdown/Signature algorithms.md @@ -0,0 +1,61 @@ + | SignatureScheme | IANA | TLS version | ('NIST', '') [^1] | ('NIST', 'from') | ('BSI', 'client/server signatures ') [^2] | ('BSI', 'use up to') | ('ANSSI', '') [^3] | ('ANSSI', 'conditions') | ('MOZILLA (+AgID)', 'Modern') | ('MOZILLA (+AgID)', 'Intermediate') | ('MOZILLA (+AgID)', 'Old') | + | :-------------------------------- | :----------- | ----------: | :--------------------------- | :--------------------- | :---------------------------------------- | :------------------- | :----------------------- | ----------------------: | :---------------------------- | :---------------------------------- | :------------------------- | + | rsa_pkcs1_sha1 | 0x0201 | 1.2 | not recommended | YEAR 2023 | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha224 | 0x0301 [^4] | 1.3 | not recommended | YEAR 2023 [^5] | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha256 | 0x0401 | 1.3 | not recommended | YEAR 2023 [^6] | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha384 | 0x0501 | 1.3 | not recommended | YEAR 2023 [^7] | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha512 | 0x0601 | 1.3 | not recommended | YEAR 2023 [^8] | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha1 | 0x0201 | 1.2 | must not | YEAR 2024 | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha224 | 0x0301 [^9] | 1.3 | must not | YEAR 2024 | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha256 | 0x0401 | 1.3 | must not | YEAR 2024 [^10] | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha384 | 0x0501 | 1.3 | must not | YEAR 2024 [^11] | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pkcs1_sha512 | 0x0601 | 1.3 | must not | YEAR 2024 [^12] | \ | YEAR 2028+ | must not | | \ | \ | \ | + | rsa_pss_rsae_sha256 | 0x0804 [^13] | 1.3 | recommended | [^14] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | rsa_pss_rsae_sha384 | 0x0805 [^15] | 1.3 | recommended | [^16] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | rsa_pss_rsae_sha512 | 0x0806 [^17] | 1.3 | recommended | [^18] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | ed25519 | 0x0807 | 1.3 | \ | [^19] | \ | YEAR 2028+ | recommended | | \ | \ | \ | + | ed448 | 0x0808 | 1.3 | \ | [^20] | \ | YEAR 2028+ | recommended | | \ | \ | \ | + | rsa_pss_pss_sha256 | 0x0809 [^21] | 1.3 | recommended | [^22] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | rsa_pss_pss_sha384 | 0x080A [^23] | 1.3 | recommended | [^24] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | rsa_pss_pss_sha512 | 0x080B [^25] | 1.3 | recommended | [^26] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | ecdsa_secp256r1_sha256 | 0x0403 | 1.3 | recommended | [^27] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | ecdsa_secp384r1_sha384 | 0x0503 | 1.3 | recommended | [^28] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | ecdsa_secp521r1_sha512 | 0x0603 | 1.3 | recommended | [^29] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | ecdsa_brainpoolP256r1tls13_sha256 | 0x081A | 1.3 | \ | [^30] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | ecdsa_brainpoolP384r1tls13_sha384 | 0x081B | 1.3 | \ | [^31] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + | ecdsa_brainpoolP512r1tls13_sha512 | 0x081C | 1.3 | \ | [^32] | recommended | YEAR 2028+ | recommended | | \ | \ | \ | + +[^1]: Partly deduced from + 3.2.1 Server Certificate Profile (Table 3.1 of 800-52r2) + together with supported groups. +[^2]: BSI-TR-02102-2, 3.4.3 +[^3]: Table 2.6 +[^4]: This signature algorithm does not exist in the IANA table it only exists in the IETF one +[^5]: [Key Agreement and Key Transport schemes based off pkcs1.5 are deprecated from 2023 and must not be used from 2024] +[^6]: [Key Agreement and Key Transport schemes based off pkcs1.5 are deprecated from 2023 and must not be used from 2024] +[^7]: [Key Agreement and Key Transport schemes based off pkcs1.5 are deprecated from 2023 and must not be used from 2024] +[^8]: [Key Agreement and Key Transport schemes based off pkcs1.5 are deprecated from 2023 and must not be used from 2024] +[^9]: This signature algorithm does not exist in the IANA table it only exists in the IETF one +[^10]: [Key Agreement and Key Transport schemes based off pkcs1.5 are deprecated from 2023 and must not be used from 2024] +[^11]: [Key Agreement and Key Transport schemes based off pkcs1.5 are deprecated from 2023 and must not be used from 2024] +[^12]: [Key Agreement and Key Transport schemes based off pkcs1.5 are deprecated from 2023 and must not be used from 2024] +[^13]: OID 1.2.840.113549.1.1.11 (deducted from RFC8446) +[^14]: approved in 800-52 (tabella 3.1) +[^15]: OID 1.2.840.113549.1.1.12 (deducted from RFC8446) +[^16]: approved in 800-52 (tabella 3.1) +[^17]: OID 1.2.840.113549.1.1.13 (deducted from RFC8446) +[^18]: approved in 800-52 (tabella 3.1) +[^19]: not mentioned until 2023 (800-186) +[^20]: not mentioned until 2023 (800-186) +[^21]: OID 1.2.840.113549.1.1.10 (deducted from RFC8446) +[^22]: approved in 800-52 (tabella 3.1) +[^23]: OID 1.2.840.113549.1.1.10 (deducted from RFC8446) +[^24]: approved in 800-52 (table 3.1) +[^25]: OID 1.2.840.113549.1.1.10 (deducted from RFC8446) +[^26]: approved in 800-52 (table 3.1) +[^27]: ecdsa and sha (>= 256) were approved in 800-52, secp* in 800-56A +[^28]: ecdsa and sha (>= 256) were approved in 800-52, secp* in 800-56A +[^29]: ecdsa and sha (>= 256) were approved in 800-52, secp* in 800-56A +[^30]: not mentioned until 2023 (800-186) +[^31]: not mentioned until 2023 (800-186) +[^32]: not mentioned until 2023 (800-186) diff --git a/markdown/Supported groups.md b/markdown/Supported groups.md new file mode 100644 index 0000000..f15925a --- /dev/null +++ b/markdown/Supported groups.md @@ -0,0 +1,46 @@ +| Mapping | IANA | supported security | ('NIST', '') [^1] | ('NIST', 'condition') | ('BSI', 'Federal applications') [^2] [^4] | ('BSI', 'Customer-facing') [^5] | ('BSI', 'Conditions') | ('ANSSI', '') [^3] | ('MOZILLA (+AgID)', 'Modern') | ('MOZILLA (+AgID)', 'Intermediate') | ('MOZILLA (+AgID)', 'Old') | +| :------------------- | :-------- | :----------------- | :--------------------------- | :------------------------------- | :----------------------------------------- | :------------------------------- | :-------------------------- | :----------------------- | :---------------------------- | :---------------------------------- | :------------------------- | +| secp224r1 / P-224 | 21 | 112 | optional | | \ | \ | | must not | not recommended | not recommended | not recommended | +| secp256r1 / P-256 | 23 | 112 - 128 | must [^6] | THIS or Groups secp384r1 / P-384 | must | recommended | | recommended | recommended | recommended | recommended | +| secp384r1 / P-384 | 24 | 112 - 192 | must [^7] | THIS or Groups secp256r1 / P-256 | recommended | recommended | | recommended | recommended | recommended | recommended | +| secp521r1 / P-521 | 25 | 112 - 256 | optional | | recommended | recommended | | recommended | not recommended | not recommended | not recommended | +| sect233k1 / K-233 | 6 | 112 - 128 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| sect283k1 / K-283 | 9 | 112 - 128 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| sect409k1 / K-409 | 11 | 112 - 192 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| sect571k1 / K-571 | 13 | 112 - 256 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| sect233r1 / B-233 | 7 | 112 - 128 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| sect283r1 / B-283 | 10 | 112 - 128 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| sect409r1 / B-409 | 12 | 112 - 192 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| sect571r1 / B-571 | 14 | 112 - 256 | optional | | | \ | | must not | not recommended | not recommended | not recommended | +| 1024-long DH | ? [^8] | ? | \ | | | \ | | must not [^9] | not recommended | not recommended | recommended | +| ffdhe2048 | 256 | 112 | optional | | recommended [^10] | recommended [^11] | YEAR 2022 [^12] | optional | not recommended | recommended | not recommended | +| ffdhe3072 | 257 | 112 - 128 | optional | | recommended | recommended | | optional | not recommended | not recommended | not recommended | +| ffdhe4096 | 258 | 112 - 152 | optional | | recommended | recommended | | optional | not recommended | not recommended | not recommended | +| ffdhe6144 | 259 | 112 - 176 | optional | | | \ | | optional | not recommended | not recommended | not recommended | +| ffdhe8192 | 260 | 112 - 200 | optional | | | \ | | optional | not recommended | not recommended | not recommended | +| brainpoolP256r1 | 26 | | recommended | | must | recommended | | optional | not recommended | not recommended | not recommended | +| brainpoolP384r1 | 27 | | recommended | | recommended | recommended | | optional | not recommended | not recommended | not recommended | +| brainpoolP512r1 | 28 | | recommended | | recommended | recommended | | optional | not recommended | not recommended | not recommended | +| X25519 / Curve25519 | 29 | | recommended | | | \ | | optional | recommended | recommended | recommended | +| X448 / Curve448 | 30 | | recommended | | | \ | | optional | not recommended | not recommended | not recommended | +| brainpoolP256r1tls13 | 31 | | recommended | | must | recommended | | optional | not recommended | not recommended | not recommended | +| brainpoolP384r1tls13 | 32 | | recommended | | recommended | recommended | | optional | not recommended | not recommended | not recommended | +| brainpoolP512r1tls13 | 33 | | recommended | | recommended | recommended | | optional | not recommended | not recommended | not recommended | + +[^1]: SP 800-56A, Appendix D +[^2]: TR-02102-2 3.3.2 +[^3]: Table 2.5 +[^4]: Technische Richtlinie BSI TR-03116 + Kryptographische Vorgaben für Projekte der Bundesregierung Teil 4 – Kommunikationsverfahren in Anwendungen + Datum: 24.01.2022 +[^5]: TR-02102-2 Version 2022-01 Section 3.2 +[^6]: either this or P-384 +[^7]: either this or P-256 +[^8]: this entry refers to user-generated DH groups so it does not have a IANA id +[^9]: Dans le cas de DHE, la sécurité de l’échange est liée à l’ordre du groupe multiplicatif en + jeu. L’attaque Logjam [4] a illustré l’insuffisance des groupes de taille 512-bits, et pousse à + déconseiller l’utilisation de groupes 1024-bits. Le RGS préconise l’utilisation de groupes 3072- + bits ou plus, et tolère les groupes 2048-bits pour une protection des données jusqu’en 2030. +[^10]: Up to 2022 +[^11]: Up to 2022 +[^12]: Use up to year 2022 diff --git a/markdown/TLS extensions.md b/markdown/TLS extensions.md new file mode 100644 index 0000000..015fadc --- /dev/null +++ b/markdown/TLS extensions.md @@ -0,0 +1,64 @@ + | ExtensionType | IANA | ('applies to version', '1.0') | ('applies to version', 1.1) | ('applies to version', 1.2) | ('applies to version', 1.3) | ('NIST', '') [^1] | ('NIST', 'condition') | ('BSI', '') | ('BSI', 'condition') | ('ANSSI', '') | ('AgID (+MOZILLA)', '') | + | :------------------------------------------- | ----: | :---------------------------- | :-------------------------- | :-------------------------- | :-------------------------- | :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- | :---------------------- | + | server_name | 0 | ✓ | ✓ | ✓ | ✓ | must | | \ | | optional | \ | + | max_fragment_length | 1 | | | | | \ | | \ | | not recommended | \ | + | client_certificate_url | 2 | ✓ | ✓ | ✓ | | not recommended | | \ | | not recommended | \ | + | trusted_ca_keys | 3 | ✓ | ✓ | ✓ | | must | CA count > 1 [^2] | \ | | optional | \ | + | truncated_hmac | 4 | ✓ | ✓ | ✓ | | optional | CIPHER CBC and VLP false and NOTE_ENABLED should only be used if the server communicates with constrained-device clients [^3] | not recommended | | not recommended | \ | + | status_request | 5 | ✓ | ✓ | ✓ | | must | | \ | | optional | recommended [^4] | + | user_mapping | 6 | ✓ | ✓ | ✓ | | \ | | \ | | optional | \ | + | client_authz | 7 | | | | | \ | | \ | | not recommended | \ | + | server_authz | 8 | | | | | \ | | \ | | not recommended | \ | + | cert_type | 9 | | | | | \ | | \ | | not recommended | \ | + | supported_groups [^5] | 10 | ✓ | ✓ | ✓ | ✓ | must | CIPHER ECDHE OR TLS 1.3 [^6] | recommended | | recommended | \ | + | ec_point_formats | 11 | ✓ | ✓ | ✓ | | must | CIPHER EC [^7] | \ | | not recommended | \ | + | srp | 12 | ✓ | ✓ | ✓ | | \ | | \ | | optional | \ | + | signature_algorithms | 13 | | | ✓ | ✓ | must | NOTE_DISABLED if this condition results as an ERROR "must be enabled" it may be a false positive. It is caused by the web server not asking the certificate to the client not allowing the tool to verify whether the extension is supported | recommended | NOTE_DISABLED if this condition results as an ERROR "must be enabled" it may be a false positive. It is caused by the web server not asking the certificate to the client not allowing the tool to verify whether the extension is supported. and NOTE_ENABLED in order for the web-server to be compliant with BSI guidelines you should enabled all the signature algorithms reccommended by BSI | recommended | \ | + | use_srtp | 14 | | | | | \ | | \ | | optional | \ | + | heartbeat | 15 | | | | | \ | | not recommended | | not recommended | not recommended | + | application_layer_protocol_negotiation | 16 | | | | | \ | | \ | | optional | \ | + | status_request_v2 [^8] | 17 | ✓ | ✓ | ✓ | | recommended | TRANSPARENCY OCSP extension [^9] | \ | | optional | \ | + | signed_certificate_timestamp | 18 | ✓ | ✓ | ✓ | ✓ | recommended | CA publicly trusted and !TRANSPARENCY TLS extension [^10] | \ | | recommended | \ | + | client_certificate_type | 19 | | | | | \ | | \ | | not recommended | \ | + | server_certificate_type | 20 | | | | | \ | | \ | | not recommended | \ | + | padding | 21 | | | | | \ | | \ | | optional | \ | + | encrypt_then_mac | 22 | ✓ | ✓ | ✓ | | must | CIPHER CBC [^11] | recommended | | recommended | \ | + | extended_master_secret | 23 | ✓ | ✓ | ✓ | | must | | recommended | | recommended | \ | + | record_size_limit | 28 | | | | | \ | | \ | | optional | \ | + | session_ticket | 35 | ✓ | ✓ | ✓ | | \ | | \ | | optional | \ | + | pre_shared_key | 41 | | | | ✓ | optional | TLS 1.3 [^12] | \ | | optional | \ | + | early_data [^13] | 42 | | | | ✓ | not recommended | | \ | | not recommended | \ | + | supported_versions | 43 | | | | ✓ | must | TLS 1.3 [^14] | \ | | recommended | \ | + | cookie | 44 | | | | ✓ | must | TLS 1.3 [^15] | \ | | optional | \ | + | psk_key_exchange_modes | 45 | | | | ✓ | must | TLS 1.3 and EXTENSION 41 [^16] | \ | | optional | \ | + | certificate_authorities | 47 | | | | ✓ | \ | | \ | | optional | \ | + | oid_filters | 48 | | | | ✓ | \ | | \ | | optional | \ | + | post_handshake_auth | 49 | | | | ✓ | optional | TLS 1.3 [^17] | \ | | optional | must not | + | signature_algorithms_cert | 50 | | | | ✓ | must | TLS 1.3 and NOTE_DISABLED if this condition results as an ERROR "must be enabled" it may be a false positive. It is caused by the web-server not asking the certificate to the client not allowing the tool to verify whether the extension is supported [^18] | optional | NOTE_ENABLED This field's level is not explicitly mentioned in the guidelines. If you want to use it in order for the web-server to be compliant with BSI guidelines you should enabled all the signature algorithms reccommended by BSI and also enable the rsa_pkcs1_sha256, rsa_pkcs1_sha384 and rsa_pkcs1_sha512 signature algorithms | optional | \ | + | signature_algorithms_cert | 50 | | | ✓ | | recommended | TLS 1.2 and NOTE_DISABLED if this condition results as an ALERT "should be enabled" it may be a false positive. It is caused by the web-server not asking the certificate to the client not allowing the tool to verify whether the extension is supported [^19] | optional | NOTE_ENABLED This field's level is not explicitly mentioned in the guidelines. If you want to use it in order for the web-server to be compliant with BSI guidelines you should enabled all the signature algorithms reccommended by BSI and also enable the rsa_pkcs1_sha256, rsa_pkcs1_sha384 and rsa_pkcs1_sha512 signature algorithms | optional | \ | + | key_share | 51 | | | | ✓ | must | TLS 1.3 [^20] | \ | | recommended | \ | + | renegotiation_info | 65281 | ✓ | ✓ | ✓ | | must | | recommended | | recommended | must | + +[^1]: 4.4 + + Extensions not needed --> should not be enabled. +[^2]: the server communicates with memory-constrained clients (e.g., low-memory client devices in the Internet of Things) AND the server has been issued certificates by multiple CAs +[^3]: the server communicates with constrained-device clients, cipher suites that use CBC mode are supported, and the server implementation does not support variable-length padding +[^4]: Inferred by the configuration generator provided by Mozilla. + The presence of SSLUseStapling and SSLStaplingCache directives enable the status_request extension +[^5]: See supported groups sheet +[^6]: the server supports ephemeral ECDH cipher suites or if the server supports TLS 1.3 +[^7]: the server supports EC cipher suites +[^8]: Multiple Certificate Status extension +[^9]: status information for the server’s certificate is available via OCSP AND the extension is supported by the server implementation +[^10]: the server’s certificate was issued by a publicly trusted CA and the certificate does not include a Signed Certificate Timestamps List extension +[^11]: the server is configured to negotiate CBC cipher suites +[^12]: the server supports TLS 1.3 +[^13]: 0-RTT data +[^14]: the server supports TLS 1.3 +[^15]: the server supports TLS 1.3 +[^16]: the server supports TLS 1.3 and the Pre-Sared Key extension +[^17]: the server supports TLS 1.3 +[^18]: the server supports TLS 1.3 +[^19]: the server supports TLS 1.2 +[^20]: the server supports TLS 1.3 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..aa9eb82 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +pandas +openpyxl +prisma \ No newline at end of file diff --git a/schema_creator.py b/schema_creator.py new file mode 100644 index 0000000..edf368e --- /dev/null +++ b/schema_creator.py @@ -0,0 +1,103 @@ +import os +import re +import subprocess +from typing import TextIO, Dict + +import pandas as pd + +from utils.configs import ( + sheets_mapping, + additional_keys, + different_templates, + RANDOM_STRING, + GUIDELINE_BLOCKS, + TEMPLATE_FILE, +) +from utils.filler_utils import ( + split_sheet, + get_requirements_columns, + get_version_name_for_database, + get_guideline_name_for_database, + read_dataframes +) + +# IMPORTANT NOTE "sheet" means the original file name, "sheet_name" is the mapped one + +# This dict is filled during the initialization +additional_templates = {} + + +# End of configurations + + +def get_block(f: TextIO): + text = "" + last_line = "a" + while last_line.lstrip() != ("}" + os.linesep) and last_line != "": + last_line = f.readline() + text += last_line + return text + + +def get_template_for(sheet: str, template: str): + template = additional_templates.get(sheet, template) + original_key_ref = "" + lines = template.splitlines() + for index, line in enumerate(lines): + if "@relation" in line: + original_key_ref = template.splitlines()[index] + for var_name in additional_keys.get(sheet, []): + new_key_ref = original_key_ref.replace("[name", f"[name, {var_name},") + new_key_ref = new_key_ref.replace(",]", "]") + template = template.replace(original_key_ref, new_key_ref) + + return template.replace("Sheet", sheet) + + +def generate_template(df: Dict[str, pd.DataFrame]): + file = open(TEMPLATE_FILE, "r") + general_part = "" + for _ in range(GUIDELINE_BLOCKS): + general_part += get_block(file) + # this part is only needed to make the template compliant to prisma guideline. + # this two regexes are only needed because the number of spaces/tabs between type and name is variable. + general_part = re.sub( + rf"Sheet{RANDOM_STRING} *Sheet{RANDOM_STRING}\[]", "", general_part + ) + for sheet in different_templates: + general_part = re.sub( + rf"{sheet}{RANDOM_STRING} *{sheet}{RANDOM_STRING}\[]", "", general_part + ) + general_part += "\n// Guidelines tables" + with open("output.prisma", "w") as f: + f.write(general_part) + # Remove the "Sheet" part that is useless + get_block(file) + # Get the general template + general_template = get_block(file) + for table in different_templates: + additional_templates[table] = get_block(file) + file.close() + for sheet in dataframe: + # sheet_name is the name that will be used in the database + sheet_name = sheets_mapping.get(sheet) + if not sheet_name: + continue + actual_template = get_template_for(sheet_name, general_template) + _, protocols_dataframe = split_sheet(df[sheet]) + requirements_columns = get_requirements_columns(protocols_dataframe, sheet) + # prepare the guidelines for the next step + for guideline in requirements_columns: + for column_name in requirements_columns[guideline]: + version_name = get_version_name_for_database(column_name) + guideline = get_guideline_name_for_database(guideline) + new_name = (guideline + version_name).upper() + with open("output.prisma", "a") as f: + f.write(actual_template.replace("7WJsEz", new_name)) + subprocess.call(["prisma", "format", "--schema=output.prisma"]) + subprocess.call(["prisma", "db", "push", "--schema=output.prisma"]) + + +if __name__ == "__main__": + dataframe = read_dataframes() + generate_template(dataframe) diff --git a/schema_generator/template.prisma b/schema_generator/template.prisma new file mode 100644 index 0000000..3bbee2f --- /dev/null +++ b/schema_generator/template.prisma @@ -0,0 +1,139 @@ +datasource db { + provider = "sqlite" + url = "file:requirements.db" +} + +// COMMON DATA +model TlsVersion { + version Float @id + ExtTls TlsVersionExtension[] + Hash Hash[] +} + +model Guideline { + name String @id + updated_at String + KeyLengths7WJsEz KeyLengths7WJsEz[] + Sheet7WJsEz Sheet7WJsEz[] + CertificateExtensions7WJsEz CertificateExtensions7WJsEz[] +} + +// GENERAL DATA +model CipherSuite { + name String @id + iana_code String + } + +model Extension { + name String @id + iana_code String + TlsVersionExtension TlsVersionExtension[] +} + +model Groups { + name String @id + iana_code String + supported_security String? +} + +model Protocol { + name String @id +} + +model Hash { + name String @id + iana_code String + tls_version Float + TlsVersion TlsVersion @relation(fields: [tls_version], references: [version]) +} + +model CertificateSignature { + name String @id + iana_code String + tls_version String +} + +model Certificate { + name String @id +} + +model CertificateExtensions { + name String @id +} + +model Misc { + name String @id +} + +model KeyLengths { + field_name String + name String + length Int + KeyLengths7WJsEz KeyLengths7WJsEz[] + + @@id([name, length]) +} + +model Signature { + name String @id + iana_code String + version String +} + +// SPECIAL TABLES +model TlsVersionExtension { + TlsVersion TlsVersion @relation(fields: [version], references: [version]) + version Float + extension Extension @relation(fields: [extension_name], references: [name]) + extension_name String + + @@id([version, extension_name]) +} + +// TEMPLATE DATA + +model Sheet { + name String @id + iana_code String + version String + Sheet7WJsEz Sheet7WJsEz[] + CertificateExtensions7WJsEz CertificateExtensions7WJsEz[] +} + +model Sheet7WJsEz { + id Int + guideline Guideline @relation(fields: [guidelineName], references: [name]) + guidelineName String + Sheet Sheet @relation(fields: [name], references: [name]) + name String + level String? // put level as Nullable (it would be considered not mentioned) + condition String? @default("") + + @@id([id, name]) +} + +model KeyLengths7WJsEz { + id Int + guideline Guideline @relation(fields: [guidelineName], references: [name]) + guidelineName String + KeyLengths KeyLengths @relation(fields: [name, length], references: [name, length]) + name String + length Int + level String? + condition String? @default("") + + @@id([id, name, length]) +} + +model CertificateExtensions7WJsEz { + id Int + guideline Guideline @relation(fields: [guidelineName], references: [name]) + guidelineName String + Sheet Sheet @relation(fields: [name], references: [name]) + name String + level String @default("") + critical String @default("no") + condition String? @default("") + + @@id([id, name]) +} diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/configs.py b/utils/configs.py new file mode 100644 index 0000000..64f8669 --- /dev/null +++ b/utils/configs.py @@ -0,0 +1,63 @@ +# schema creator configs +TEMPLATE_FILE = "schema_generator/template.prisma" +GUIDELINE_BLOCKS = 15 +RANDOM_STRING = "7WJsEz" + +# list of sheet_names that need a different template, order is important +different_templates = ["KeyLengths", "CertificateExtensions"] + +# The syntax for this is: Sheet: list of keys +# it is assumed that a field with the same name of the key was added using the additional_fields dict +additional_keys = { +} + +guidelines = { + "NIST": "", + "ANSSI": "", + "AgID": "", + "BSI": "", + "Mozilla": "" +} + +levels_mapping = { + "1": "must", + "2": "must not", + "3": "recommended", + "4": "not recommended", + "5": "optional", + "6": "" +} + +sheets_mapping = { + "Protocols": "Protocol", + "Cipher Suites": "CipherSuite", + "TLS extensions": "Extension", + "Supported groups": "Groups", + "Signature algorithms": "Signature", + "Hash Algorithm": "Hash", + "Certificate Signature": "CertificateSignature", + "Key lengths": "KeyLengths", + "Certificate": "Certificate", + "Certificate Extensions": "CertificateExtensions", + "Misc": "Misc" +} + +# give both pos to start and number of columns to get +different_names_pos = { + "Key lengths": (1, 2) +} + +# If a sheet has some columns that should be considered as guideline "versions" but don't use the usual syntax they +# can be set in a list in a dictionary with "guideline": [col_index1, col_index2] that appears as a value for the +# respective sheet +sheet_columns = { + "Cipher Suites": { + "NIST": [1, 2, 3], + "BSI": [1, 2, 3] + }, +} + +converters = { + # this function is needed to avoid having iana codes in the form 0.0 + ('IANA', ''): lambda x: str(int(x)) if isinstance(x, float) else str(x) +} diff --git a/utils/filler_utils.py b/utils/filler_utils.py new file mode 100644 index 0000000..898784b --- /dev/null +++ b/utils/filler_utils.py @@ -0,0 +1,183 @@ +from typing import Dict, List + +import re, io + +import pandas as pd + +from .configs import guidelines, levels_mapping, sheet_columns, sheets_mapping + + +def split_sheet(sheet: pd.DataFrame): + """ + Splits the sheet at the first guideline column to have two dataframes one with general data and the other with the + data of the guidelines. + :param sheet: the sheet that needs to be split + :return: the two dataframes + """ + guideline_column_index = get_first_guideline_column_pos(sheet) + # This split is done to make things more organised + general_dataframe: pd.DataFrame = sheet.iloc[:, :guideline_column_index] + protocols_dataframe: pd.DataFrame = sheet.iloc[:, guideline_column_index:] + return general_dataframe, protocols_dataframe + + +def get_requirements_columns(requirements_df: pd.DataFrame, sheet_name: str) -> Dict[str, List[str]]: + """Returns a dictionary containing Guideline_name as key and a list composed of columns that contain evaluations""" + # Get the first row (after the header) of the dataframe and convert it to a dict for easier access + row_dict = requirements_df.iloc[0:1, :].to_dict() + result_dict = {} + # col is the header so col[0] is the guideline_name and col[1] is the actual column name + for col in row_dict: + also_add = [] + if " " in col[0]: + parts = col[0].split(" ") + if "+" in parts[1]: + for el in parts[1].split("+")[1:]: + also_add.append(el.strip(")")) + if not result_dict.get(col[0]): + result_dict[col[0]] = [] + val = row_dict[col] + if get_standardized_level(val[0]) in levels_mapping.values(): + result_dict[col[0]].append(col[1]) + for val in also_add: + if not result_dict.get(val): + result_dict[val] = [] + result_dict[val].append(col[1]) + for guideline in result_dict: + valid_indexes = sheet_columns.get(sheet_name, {}).get(guideline) + if valid_indexes: + result_dict[guideline] = get_column_names_from_indexes(requirements_df, guideline, valid_indexes) + return result_dict + + +def get_columns_count_for_guideline(df: pd.DataFrame) -> Dict: + """The header may have the same value at index 0 (the guideline) with different values at index 1. So it is useful to + know how many columns each guideline uses. + :param df Pandas dataframe. Specifically the guideline specific one. + """ + results = {} + values_count_dict = df.columns.value_counts() + for col in values_count_dict.keys(): + if results.get(col[0]): + results[col[0]] += values_count_dict[col] + else: + results[col[0]] = values_count_dict[col] + return results + + +def get_first_guideline_column_pos(s: pd.DataFrame): + """Searches the first column in the dataframe that contains guideline specific data and returns its index. + :param s: The dataframe in which the column should be searched + """ + for i, c in enumerate(s.columns): + first_row = c[0] + c_name = first_row.split(" ")[0] if " " in first_row else first_row + if c_name.lower() in [g.lower() for g in guidelines]: + return i + # Maybe should raise an exception + return -1 + + +def get_column_names_from_indexes(requirements_df: pd.DataFrame, guideline_name: str, valid_indexes: List[int]) -> \ + List[str]: + """ + This function returns the names of the columns from its indexes. + At the moment it is only used to get the column names for the sheets that have requirements columns that don't + contain guideline values such as "Cipher Suites" + :param requirements_df: The dataframe in which the research should be done + :param guideline_name: The name of the guideline to search + :param valid_indexes: The indexes to search the name for + :return: + """ + row_dict = requirements_df.iloc[0:1, :].to_dict() + columns = [] + i = 0 + for col in row_dict: + if col[0] == guideline_name: + if i in valid_indexes: + columns.append(col[1]) + i += 1 + return columns + + +def get_version_name_for_database(version_name: str): + """This function prepares the version_name to be usable in the database as art of a table's name""" + version_name = version_name if "Unnamed" not in version_name else "" + version_name = version_name.strip().title().replace(" ", "").replace("-", "").replace("/", "_").replace("#", "") \ + .strip(".") + return version_name.upper() + + +def get_guideline_name_for_database(guideline: str): + """This function prepares the guideline_name to be usable in the database as part of a table's name""" + if " " in guideline: + tokens = guideline.split(" ") + if "+" in tokens[1]: + # The "added" entries are already present in the dict + guideline = tokens[0] + elif len(tokens) > 2 and "/" in tokens[-1]: + guideline = tokens[0] + tokens[-1].replace("/", "_") + return guideline.strip(")").upper() + + +def is_double_guideline(guideline: str): + return " " in guideline and guideline.split(" ")[1][1] == "+" + + +def get_first_col_for_guideline(df: pd.DataFrame, guideline: str): + for col in df.columns: + if col[0] == guideline: + return col[1] + + +def get_column(df: pd.DataFrame, index: int): + return df.iloc[:, index] + +def get_standardized_level(level): + """ + Takes a level in input and returns it after removing °,* and trailing spaces + :param level: + :type level: str + :return: + """ + if isinstance(level, str): + return level.replace("*", "").replace("°", "").strip() + else: + return "" + +def clean_string(string: str): + while "^" in string: + string = re.sub(r'\[.\d+\]', '', string) + return string.strip().strip("(").strip(")").strip("'").strip() + +def single_string_clean(string: str): + # the other function removes important characters + while "^" in string: + string = re.sub(r'\[.\d+]', '', string) + return string.strip().strip("'") + + +def read_dataframes(additional_args: Dict = {}): + dataframe = {} + for sheet in sheets_mapping: + with open(f'markdown/{sheet}.md', 'r') as file: + lines = file.readlines() + stop_at = None + for line in enumerate(lines): + lines[line[0]] = lines[line[0]].replace("\\", "") + lines[line[0]] = re.sub(r'\[.\d+\]', '', lines[line[0]]) + if not line[1].strip().startswith("|"): + stop_at = line[0] + break + if stop_at: + lines = lines[:stop_at] + buffer = io.StringIO("".join(lines)) + tmp_df = pd.read_table(buffer, sep="|", header=[0,1], skipinitialspace=True, **additional_args) + tmp_df.columns = tmp_df.columns.droplevel(1) + tmp_df.pop("Unnamed: 0_level_0") + tmp_df.pop(tmp_df.columns[-1]) + tuples = [x.split(",") for x in tmp_df.columns.to_list()] + tuples = [(clean_string(x[0]), clean_string(x[1])) if len(x) == 2 else (single_string_clean(x[0]), '') for x in tuples] + tmp_df.columns = pd.MultiIndex.from_tuples(tuples) + dataframe[sheet] = tmp_df + return dataframe \ No newline at end of file