LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/algorithms - publickey.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 76 76 100.0 %
Date: 2020-10-30 04:50:48 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2011-2012 Free Software Foundation, Inc.
       3             :  *
       4             :  * Author: Nikos Mavrogiannopoulos
       5             :  *
       6             :  * This file is part of GnuTLS.
       7             :  *
       8             :  * The GnuTLS is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public License
      10             :  * as published by the Free Software Foundation; either version 2.1 of
      11             :  * the License, or (at your option) any later version.
      12             :  *
      13             :  * This library is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public License
      19             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      20             :  *
      21             :  */
      22             : 
      23             : #include "gnutls_int.h"
      24             : #include <algorithms.h>
      25             : #include "errors.h"
      26             : #include <x509/common.h>
      27             : 
      28             : 
      29             : /* KX mappings to PK algorithms */
      30             : typedef struct {
      31             :         gnutls_kx_algorithm_t kx_algorithm;
      32             :         gnutls_pk_algorithm_t pk_algorithm;
      33             :         enum encipher_type encipher_type;       /* CIPHER_ENCRYPT if this algorithm is to be used
      34             :                                                  * for encryption, CIPHER_SIGN if signature only,
      35             :                                                  * CIPHER_IGN if this does not apply at all.
      36             :                                                  *
      37             :                                                  * This is useful to certificate cipher suites, which check
      38             :                                                  * against the certificate key usage bits.
      39             :                                                  */
      40             : } gnutls_pk_map;
      41             : 
      42             : /* This table maps the Key exchange algorithms to
      43             :  * the certificate algorithms. Eg. if we have
      44             :  * RSA algorithm in the certificate then we can
      45             :  * use GNUTLS_KX_RSA or GNUTLS_KX_DHE_RSA.
      46             :  */
      47             : static const gnutls_pk_map pk_mappings[] = {
      48             :         {GNUTLS_KX_RSA, GNUTLS_PK_RSA, CIPHER_ENCRYPT},
      49             :         {GNUTLS_KX_DHE_RSA, GNUTLS_PK_RSA, CIPHER_SIGN},
      50             :         {GNUTLS_KX_SRP_RSA, GNUTLS_PK_RSA, CIPHER_SIGN},
      51             :         {GNUTLS_KX_ECDHE_RSA, GNUTLS_PK_RSA, CIPHER_SIGN},
      52             :         {GNUTLS_KX_ECDHE_ECDSA, GNUTLS_PK_EC, CIPHER_SIGN},
      53             :         {GNUTLS_KX_ECDHE_ECDSA, GNUTLS_PK_EDDSA_ED25519, CIPHER_SIGN},
      54             :         {GNUTLS_KX_ECDHE_ECDSA, GNUTLS_PK_EDDSA_ED448, CIPHER_SIGN},
      55             :         {GNUTLS_KX_DHE_DSS, GNUTLS_PK_DSA, CIPHER_SIGN},
      56             :         {GNUTLS_KX_DHE_RSA, GNUTLS_PK_RSA_PSS, CIPHER_SIGN},
      57             :         {GNUTLS_KX_ECDHE_RSA, GNUTLS_PK_RSA_PSS, CIPHER_SIGN},
      58             :         {GNUTLS_KX_SRP_DSS, GNUTLS_PK_DSA, CIPHER_SIGN},
      59             :         {GNUTLS_KX_RSA_PSK, GNUTLS_PK_RSA, CIPHER_ENCRYPT},
      60             :         {GNUTLS_KX_VKO_GOST_12, GNUTLS_PK_GOST_01, CIPHER_SIGN},
      61             :         {GNUTLS_KX_VKO_GOST_12, GNUTLS_PK_GOST_12_256, CIPHER_SIGN},
      62             :         {GNUTLS_KX_VKO_GOST_12, GNUTLS_PK_GOST_12_512, CIPHER_SIGN},
      63             :         {0, 0, 0}
      64             : };
      65             : 
      66             : #define GNUTLS_PK_MAP_LOOP(b) \
      67             :         const gnutls_pk_map *p; \
      68             :                 for(p = pk_mappings; p->kx_algorithm != 0; p++) { b }
      69             : 
      70             : #define GNUTLS_PK_MAP_ALG_LOOP(a) \
      71             :                         GNUTLS_PK_MAP_LOOP( if(p->kx_algorithm == kx_algorithm) { a; break; })
      72             : 
      73             : 
      74             : unsigned
      75        1215 : _gnutls_kx_supports_pk(gnutls_kx_algorithm_t kx_algorithm,
      76             :                        gnutls_pk_algorithm_t pk_algorithm)
      77             : {
      78        5016 :         GNUTLS_PK_MAP_LOOP(if (p->kx_algorithm == kx_algorithm && p->pk_algorithm == pk_algorithm) { return 1; })
      79             :         return 0;
      80             : }
      81             : 
      82             : unsigned
      83       18894 : _gnutls_kx_supports_pk_usage(gnutls_kx_algorithm_t kx_algorithm,
      84             :                              gnutls_pk_algorithm_t pk_algorithm,
      85             :                              unsigned int key_usage)
      86             : {
      87       18894 :         const gnutls_pk_map *p;
      88             : 
      89      174501 :         for(p = pk_mappings; p->kx_algorithm != 0; p++) {
      90      165464 :                 if (p->kx_algorithm == kx_algorithm && p->pk_algorithm == pk_algorithm) {
      91        9857 :                         if (key_usage == 0)
      92             :                                 return 1;
      93        4484 :                         else if (p->encipher_type == CIPHER_SIGN && (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE))
      94             :                                 return 1;
      95         577 :                         else if (p->encipher_type == CIPHER_ENCRYPT && (key_usage & GNUTLS_KEY_KEY_ENCIPHERMENT))
      96             :                                 return 1;
      97             :                         else
      98          97 :                                 return 0;
      99             :                 }
     100             :         }
     101             : 
     102             :         return 0;
     103             : }
     104             : 
     105             : /* pk algorithms;
     106             :  */
     107             : struct gnutls_pk_entry {
     108             :         const char *name;
     109             :         const char *oid;
     110             :         gnutls_pk_algorithm_t id;
     111             :         gnutls_ecc_curve_t curve; /* to map PK to specific OID, we need to know the curve for EdDSA */
     112             :         bool no_prehashed; /* non-zero if the algorithm cannot sign pre-hashed data */
     113             : };
     114             : typedef struct gnutls_pk_entry gnutls_pk_entry;
     115             : 
     116             : static const gnutls_pk_entry pk_algorithms[] = {
     117             :         /* having duplicate entries is ok, as long as the one
     118             :          * we want to return OID from is first */
     119             :         { .name = "RSA", .oid = PK_PKIX1_RSA_OID, .id = GNUTLS_PK_RSA,
     120             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     121             :         { .name = "RSA-PSS", .oid = PK_PKIX1_RSA_PSS_OID, .id = GNUTLS_PK_RSA_PSS,
     122             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     123             :         { .name = "RSA (X.509)", .oid = PK_X509_RSA_OID, .id = GNUTLS_PK_RSA,
     124             :            .curve = GNUTLS_ECC_CURVE_INVALID }, /* some certificates use this OID for RSA */
     125             :         { .name = "RSA-MD5", .oid = SIG_RSA_MD5_OID, .id = GNUTLS_PK_RSA,
     126             :            .curve = GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with MD5 as an indicator of RSA */
     127             :         { .name = "RSA-SHA1", .oid = SIG_RSA_SHA1_OID, .id = GNUTLS_PK_RSA,
     128             :            .curve = GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
     129             :         { .name = "RSA-SHA1", .oid = ISO_SIG_RSA_SHA1_OID, .id = GNUTLS_PK_RSA,
     130             :            .curve = GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
     131             :         { .name = "DSA", .oid = PK_DSA_OID, .id = GNUTLS_PK_DSA,
     132             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     133             :         { .name = "GOST R 34.10-2012-512", .oid = PK_GOST_R3410_2012_512_OID, .id = GNUTLS_PK_GOST_12_512,
     134             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     135             :         { .name = "GOST R 34.10-2012-256", .oid = PK_GOST_R3410_2012_256_OID, .id = GNUTLS_PK_GOST_12_256,
     136             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     137             :         { .name = "GOST R 34.10-2001", .oid = PK_GOST_R3410_2001_OID, .id = GNUTLS_PK_GOST_01,
     138             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     139             :         { .name = "GOST R 34.10-94", .oid = PK_GOST_R3410_94_OID, .id = GNUTLS_PK_UNKNOWN,
     140             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     141             :         { .name = "EC/ECDSA", .oid = "1.2.840.10045.2.1", .id = GNUTLS_PK_ECDSA,
     142             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     143             :         { .name = "EdDSA (Ed25519)", .oid = SIG_EDDSA_SHA512_OID, .id = GNUTLS_PK_EDDSA_ED25519, 
     144             :           .curve = GNUTLS_ECC_CURVE_ED25519, .no_prehashed = 1 },
     145             :         { .name = "EdDSA (Ed448)", .oid = SIG_ED448_OID, .id = GNUTLS_PK_EDDSA_ED448,
     146             :           .curve = GNUTLS_ECC_CURVE_ED448, .no_prehashed = 1 },
     147             :         { .name = "DH", .oid = NULL, .id = GNUTLS_PK_DH,
     148             :            .curve = GNUTLS_ECC_CURVE_INVALID },
     149             :         { .name = "ECDH (X25519)", .oid = "1.3.101.110", .id = GNUTLS_PK_ECDH_X25519,
     150             :           .curve = GNUTLS_ECC_CURVE_X25519 },
     151             :         { .name = "ECDH (X448)", .oid = "1.3.101.111", .id = GNUTLS_PK_ECDH_X448,
     152             :           .curve = GNUTLS_ECC_CURVE_X448 },
     153             :         { .name = "UNKNOWN", .oid = NULL, .id = GNUTLS_PK_UNKNOWN, 
     154             :           .curve = GNUTLS_ECC_CURVE_INVALID },
     155             :         {0, 0, 0, 0}
     156             : };
     157             : 
     158             : #define GNUTLS_PK_LOOP(b) \
     159             :         { const gnutls_pk_entry *p; \
     160             :                 for(p = pk_algorithms; p->name != NULL; p++) { b ; } }
     161             : 
     162             : 
     163             : /**
     164             :  * gnutls_pk_algorithm_get_name:
     165             :  * @algorithm: is a pk algorithm
     166             :  *
     167             :  * Convert a #gnutls_pk_algorithm_t value to a string.
     168             :  *
     169             :  * Returns: a string that contains the name of the specified public
     170             :  *   key algorithm, or %NULL.
     171             :  **/
     172        1914 : const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm)
     173             : {
     174        1914 :         const char *ret = NULL;
     175             : 
     176        5187 :         GNUTLS_PK_LOOP(
     177             :                 if (p->id == algorithm) {
     178             :                         ret = p->name;
     179             :                         break;
     180             :                 }
     181        1914 :         );
     182             : 
     183        1914 :         return ret;
     184             : }
     185             : 
     186             : /**
     187             :  * gnutls_pk_list:
     188             :  *
     189             :  * Get a list of supported public key algorithms.
     190             :  *
     191             :  * This function is not thread safe.
     192             :  *
     193             :  * Returns: a (0)-terminated list of #gnutls_pk_algorithm_t integers
     194             :  *   indicating the available ciphers.
     195             :  *
     196             :  * Since: 2.6.0
     197             :  **/
     198           3 : const gnutls_pk_algorithm_t *gnutls_pk_list(void)
     199             : {
     200           3 :         static gnutls_pk_algorithm_t supported_pks[MAX_ALGOS] = { 0 };
     201             : 
     202           3 :         if (supported_pks[0] == 0) {
     203             :                 int i = 0;
     204             : 
     205          57 :                 GNUTLS_PK_LOOP(
     206             :                         if (p->id != GNUTLS_PK_UNKNOWN && supported_pks[i > 0 ? (i - 1) : 0] != p->id)
     207             :                                 supported_pks[i++] = p->id
     208           3 :                 );
     209           3 :                 supported_pks[i++] = 0;
     210             :         }
     211             : 
     212           3 :         return supported_pks;
     213             : }
     214             : 
     215             : /**
     216             :  * gnutls_pk_get_id:
     217             :  * @name: is a string containing a public key algorithm name.
     218             :  *
     219             :  * Convert a string to a #gnutls_pk_algorithm_t value.  The names are
     220             :  * compared in a case insensitive way.  For example,
     221             :  * gnutls_pk_get_id("RSA") will return %GNUTLS_PK_RSA.
     222             :  *
     223             :  * Returns: a #gnutls_pk_algorithm_t id of the specified public key
     224             :  *   algorithm string, or %GNUTLS_PK_UNKNOWN on failures.
     225             :  *
     226             :  * Since: 2.6.0
     227             :  **/
     228          14 : gnutls_pk_algorithm_t gnutls_pk_get_id(const char *name)
     229             : {
     230          14 :         gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
     231          14 :         const gnutls_pk_entry *p;
     232             : 
     233         144 :         for (p = pk_algorithms; p->name != NULL; p++)
     234         143 :                 if (name && strcmp(p->name, name) == 0) {
     235          13 :                         ret = p->id;
     236          13 :                         break;
     237             :                 }
     238             : 
     239          14 :         return ret;
     240             : }
     241             : 
     242             : /**
     243             :  * gnutls_pk_get_name:
     244             :  * @algorithm: is a public key algorithm
     245             :  *
     246             :  * Convert a #gnutls_pk_algorithm_t value to a string.
     247             :  *
     248             :  * Returns: a pointer to a string that contains the name of the
     249             :  *   specified public key algorithm, or %NULL.
     250             :  *
     251             :  * Since: 2.6.0
     252             :  **/
     253       18331 : const char *gnutls_pk_get_name(gnutls_pk_algorithm_t algorithm)
     254             : {
     255       18331 :         const char *ret = "Unknown";
     256       18331 :         const gnutls_pk_entry *p;
     257             : 
     258       28691 :         for (p = pk_algorithms; p->name != NULL; p++)
     259       28691 :                 if (algorithm == p->id) {
     260             :                         ret = p->name;
     261             :                         break;
     262             :                 }
     263             : 
     264       18331 :         return ret;
     265             : }
     266             : 
     267             : /*-
     268             :  * _gnutls_pk_is_not_prehashed:
     269             :  * @algorithm: is a public key algorithm
     270             :  *
     271             :  * Returns non-zero when the public key algorithm does not support pre-hashed
     272             :  * data.
     273             :  *
     274             :  * Since: 3.6.0
     275             :  **/
     276       20803 : bool _gnutls_pk_is_not_prehashed(gnutls_pk_algorithm_t algorithm)
     277             : {
     278       20803 :         const gnutls_pk_entry *p;
     279             : 
     280      106474 :         for (p = pk_algorithms; p->name != NULL; p++)
     281      106474 :                 if (algorithm == p->id) {
     282       20803 :                         return p->no_prehashed;
     283             :                 }
     284             : 
     285             :         return 0;
     286             : }
     287             : 
     288             : /**
     289             :  * gnutls_oid_to_pk:
     290             :  * @oid: is an object identifier
     291             :  *
     292             :  * Converts a textual object identifier to a #gnutls_pk_algorithm_t value.
     293             :  *
     294             :  * Returns: a #gnutls_pk_algorithm_t id of the specified digest
     295             :  *   algorithm, or %GNUTLS_PK_UNKNOWN on failure.
     296             :  *
     297             :  * Since: 3.4.3
     298             :  **/
     299        5274 : gnutls_pk_algorithm_t gnutls_oid_to_pk(const char *oid)
     300             : {
     301        5274 :         gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
     302        5274 :         const gnutls_pk_entry *p;
     303             : 
     304       57225 :         for (p = pk_algorithms; p->name != NULL; p++)
     305       57220 :                 if (p->oid && strcmp(p->oid, oid) == 0) {
     306        5269 :                         ret = p->id;
     307        5269 :                         break;
     308             :                 }
     309             : 
     310        5274 :         return ret;
     311             : }
     312             : 
     313             : /**
     314             :  * gnutls_pk_get_oid:
     315             :  * @algorithm: is a public key algorithm
     316             :  *
     317             :  * Convert a #gnutls_pk_algorithm_t value to its object identifier string.
     318             :  *
     319             :  * Returns: a pointer to a string that contains the object identifier of the
     320             :  *   specified public key algorithm, or %NULL.
     321             :  *
     322             :  * Since: 3.4.3
     323             :  **/
     324        5063 : const char *gnutls_pk_get_oid(gnutls_pk_algorithm_t algorithm)
     325             : {
     326        5063 :         const char *ret = NULL;
     327        5063 :         const gnutls_pk_entry *p;
     328             : 
     329        5063 :         if (algorithm == 0)
     330             :                 return NULL;
     331             : 
     332       17121 :         for (p = pk_algorithms; p->name != NULL; p++)
     333       17121 :                 if (p->id == algorithm) {
     334        5062 :                         ret = p->oid;
     335        5062 :                         break;
     336             :                 }
     337             : 
     338             :         return ret;
     339             : }
     340             : 
     341             : /*-
     342             :  * _gnutls_oid_to_pk_and_curve:
     343             :  * @oid: is an object identifier
     344             :  *
     345             :  * Convert an OID to a #gnutls_pk_algorithm_t and curve values. If no curve
     346             :  * is applicable, curve will be set GNUTLS_ECC_CURVE_INVALID.
     347             :  *
     348             :  * Returns: a #gnutls_pk_algorithm_t id of the specified digest
     349             :  *   algorithm, or %GNUTLS_PK_UNKNOWN on failure.
     350             :  *
     351             :  * Since: 3.6.0
     352             :  -*/
     353       66493 : gnutls_pk_algorithm_t _gnutls_oid_to_pk_and_curve(const char *oid, gnutls_ecc_curve_t *curve)
     354             : {
     355       66493 :         gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
     356       66493 :         const gnutls_pk_entry *p;
     357             : 
     358      311793 :         for (p = pk_algorithms; p->name != NULL; p++)
     359      311475 :                 if (p->oid && strcmp(p->oid, oid) == 0) {
     360       66175 :                         ret = p->id;
     361       66175 :                         if (curve)
     362       66175 :                                 *curve = p->curve;
     363             :                         break;
     364             :                 }
     365             : 
     366       66493 :         if (ret == GNUTLS_PK_UNKNOWN && curve)
     367         326 :                 *curve = GNUTLS_ECC_CURVE_INVALID;
     368             : 
     369       66493 :         return ret;
     370             : }
     371             : 
     372             : /* Returns the encipher type for the given key exchange algorithm.
     373             :  * That one of CIPHER_ENCRYPT, CIPHER_SIGN, CIPHER_IGN.
     374             :  *
     375             :  * ex. GNUTLS_KX_RSA requires a certificate able to encrypt... so returns CIPHER_ENCRYPT.
     376             :  */
     377             : enum encipher_type
     378        9760 : _gnutls_kx_encipher_type(gnutls_kx_algorithm_t kx_algorithm)
     379             : {
     380        9760 :         int ret = CIPHER_IGN;
     381       26796 :         GNUTLS_PK_MAP_ALG_LOOP(ret = p->encipher_type)
     382             : 
     383        9760 :         return ret;
     384             : 
     385             : }
     386             : 
     387          28 : bool _gnutls_pk_are_compat(gnutls_pk_algorithm_t pk1, gnutls_pk_algorithm_t pk2)
     388             : {
     389          28 :         if (pk1 == pk2)
     390             :                 return 1;
     391             : 
     392           8 :         if (GNUTLS_PK_IS_RSA(pk1) && GNUTLS_PK_IS_RSA(pk2))
     393           8 :                 return 1;
     394             : 
     395             :         return 0;
     396             : }

Generated by: LCOV version 1.14