/*
* Copyright (C) 2011-2012 Free Software Foundation, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GnuTLS.
*
* The GnuTLS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see
*
*/
#include "gnutls_int.h"
#include
#include "errors.h"
#include
/* signature algorithms;
*/
struct gnutls_sign_entry {
const char *name;
const char *oid;
gnutls_sign_algorithm_t id;
gnutls_pk_algorithm_t pk;
gnutls_digest_algorithm_t mac;
/* See RFC 5246 HashAlgorithm and SignatureAlgorithm
for values to use in aid struct. */
const sign_algorithm_st aid;
};
typedef struct gnutls_sign_entry gnutls_sign_entry;
#define TLS_SIGN_AID_UNKNOWN {255, 255}
static const sign_algorithm_st unknown_tls_aid = TLS_SIGN_AID_UNKNOWN;
static const gnutls_sign_entry sign_algorithms[] = {
{"RSA-SHA1", SIG_RSA_SHA1_OID, GNUTLS_SIGN_RSA_SHA1, GNUTLS_PK_RSA,
GNUTLS_DIG_SHA1, {2, 1}},
{"RSA-SHA1", ISO_SIG_RSA_SHA1_OID, GNUTLS_SIGN_RSA_SHA1,
GNUTLS_PK_RSA,
GNUTLS_DIG_SHA1, {2, 1}},
{"RSA-SHA224", SIG_RSA_SHA224_OID, GNUTLS_SIGN_RSA_SHA224,
GNUTLS_PK_RSA,
GNUTLS_DIG_SHA224, {3, 1}},
{"RSA-SHA256", SIG_RSA_SHA256_OID, GNUTLS_SIGN_RSA_SHA256,
GNUTLS_PK_RSA,
GNUTLS_DIG_SHA256, {4, 1}},
{"RSA-SHA384", SIG_RSA_SHA384_OID, GNUTLS_SIGN_RSA_SHA384,
GNUTLS_PK_RSA,
GNUTLS_DIG_SHA384, {5, 1}},
{"RSA-SHA512", SIG_RSA_SHA512_OID, GNUTLS_SIGN_RSA_SHA512,
GNUTLS_PK_RSA,
GNUTLS_DIG_SHA512, {6, 1}},
{"RSA-RMD160", SIG_RSA_RMD160_OID, GNUTLS_SIGN_RSA_RMD160,
GNUTLS_PK_RSA,
GNUTLS_DIG_RMD160, TLS_SIGN_AID_UNKNOWN},
{"DSA-SHA1", SIG_DSA_SHA1_OID, GNUTLS_SIGN_DSA_SHA1, GNUTLS_PK_DSA,
GNUTLS_DIG_SHA1, {2, 2}},
{"DSA-SHA1", "1.3.14.3.2.27", GNUTLS_SIGN_DSA_SHA1, GNUTLS_PK_DSA,
GNUTLS_DIG_SHA1, {2, 2}},
{"DSA-SHA224", SIG_DSA_SHA224_OID, GNUTLS_SIGN_DSA_SHA224,
GNUTLS_PK_DSA,
GNUTLS_DIG_SHA224, {3, 2}},
{"DSA-SHA256", SIG_DSA_SHA256_OID, GNUTLS_SIGN_DSA_SHA256,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA256, {4, 2}},
{"RSA-MD5", SIG_RSA_MD5_OID, GNUTLS_SIGN_RSA_MD5, GNUTLS_PK_RSA,
GNUTLS_DIG_MD5, {1, 1}},
{"RSA-MD5", "1.3.14.3.2.25", GNUTLS_SIGN_RSA_MD5, GNUTLS_PK_RSA,
GNUTLS_DIG_MD5, {1, 1}},
{"RSA-MD2", SIG_RSA_MD2_OID, GNUTLS_SIGN_RSA_MD2, GNUTLS_PK_RSA,
GNUTLS_DIG_MD2, TLS_SIGN_AID_UNKNOWN},
{"ECDSA-SHA1", "1.2.840.10045.4.1", GNUTLS_SIGN_ECDSA_SHA1,
GNUTLS_PK_EC, GNUTLS_DIG_SHA1, {2, 3}},
{"ECDSA-SHA224", "1.2.840.10045.4.3.1", GNUTLS_SIGN_ECDSA_SHA224,
GNUTLS_PK_EC, GNUTLS_DIG_SHA224, {3, 3}},
{"ECDSA-SHA256", "1.2.840.10045.4.3.2", GNUTLS_SIGN_ECDSA_SHA256,
GNUTLS_PK_EC, GNUTLS_DIG_SHA256, {4, 3}},
{"ECDSA-SHA384", "1.2.840.10045.4.3.3", GNUTLS_SIGN_ECDSA_SHA384,
GNUTLS_PK_EC, GNUTLS_DIG_SHA384, {5, 3}},
{"ECDSA-SHA512", "1.2.840.10045.4.3.4", GNUTLS_SIGN_ECDSA_SHA512,
GNUTLS_PK_EC, GNUTLS_DIG_SHA512, {6, 3}},
{"GOST R 34.10-2001", SIG_GOST_R3410_2001_OID, 0, 0, 0,
TLS_SIGN_AID_UNKNOWN},
{"GOST R 34.10-94", SIG_GOST_R3410_94_OID, 0, 0, 0,
TLS_SIGN_AID_UNKNOWN},
{"DSA-SHA384", SIG_DSA_SHA384_OID, GNUTLS_SIGN_DSA_SHA384,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA384, {5, 2}},
{"DSA-SHA512", SIG_DSA_SHA512_OID, GNUTLS_SIGN_DSA_SHA512,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA512, {6, 2}},
{"ECDSA-SHA3-224", SIG_ECDSA_SHA3_224_OID, GNUTLS_SIGN_ECDSA_SHA3_224,
GNUTLS_PK_EC, GNUTLS_DIG_SHA3_224, TLS_SIGN_AID_UNKNOWN},
{"ECDSA-SHA3-256", SIG_ECDSA_SHA3_256_OID, GNUTLS_SIGN_ECDSA_SHA3_256,
GNUTLS_PK_EC, GNUTLS_DIG_SHA3_256, TLS_SIGN_AID_UNKNOWN},
{"ECDSA-SHA3-384", SIG_ECDSA_SHA3_384_OID, GNUTLS_SIGN_ECDSA_SHA3_384,
GNUTLS_PK_EC, GNUTLS_DIG_SHA3_384, TLS_SIGN_AID_UNKNOWN},
{"ECDSA-SHA3-512", SIG_ECDSA_SHA3_512_OID, GNUTLS_SIGN_ECDSA_SHA3_512,
GNUTLS_PK_EC, GNUTLS_DIG_SHA3_512, TLS_SIGN_AID_UNKNOWN},
{"RSA-SHA3-224", SIG_RSA_SHA3_224_OID, GNUTLS_SIGN_RSA_SHA3_224,
GNUTLS_PK_RSA, GNUTLS_DIG_SHA3_224, TLS_SIGN_AID_UNKNOWN},
{"RSA-SHA3-256", SIG_RSA_SHA3_256_OID, GNUTLS_SIGN_RSA_SHA3_256,
GNUTLS_PK_RSA, GNUTLS_DIG_SHA3_256, TLS_SIGN_AID_UNKNOWN},
{"RSA-SHA3-384", SIG_RSA_SHA3_384_OID, GNUTLS_SIGN_RSA_SHA3_384,
GNUTLS_PK_RSA, GNUTLS_DIG_SHA3_384, TLS_SIGN_AID_UNKNOWN},
{"RSA-SHA3-512", SIG_RSA_SHA3_512_OID, GNUTLS_SIGN_RSA_SHA3_512,
GNUTLS_PK_RSA, GNUTLS_DIG_SHA3_512, TLS_SIGN_AID_UNKNOWN},
{"DSA-SHA3-224", SIG_DSA_SHA3_224_OID, GNUTLS_SIGN_DSA_SHA3_224,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA3_224, TLS_SIGN_AID_UNKNOWN},
{"DSA-SHA3-256", SIG_DSA_SHA3_256_OID, GNUTLS_SIGN_DSA_SHA3_256,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA3_256, TLS_SIGN_AID_UNKNOWN},
{"DSA-SHA3-384", SIG_DSA_SHA3_384_OID, GNUTLS_SIGN_DSA_SHA3_384,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA3_384, TLS_SIGN_AID_UNKNOWN},
{"DSA-SHA3-512", SIG_DSA_SHA3_512_OID, GNUTLS_SIGN_DSA_SHA3_512,
GNUTLS_PK_DSA, GNUTLS_DIG_SHA3_512, TLS_SIGN_AID_UNKNOWN},
{"RSA-PSS-SHA256", PK_PKIX1_RSA_PSS_OID, GNUTLS_SIGN_RSA_PSS_SHA256,
GNUTLS_PK_RSA_PSS,
GNUTLS_DIG_SHA256, {8, 4}},
{"RSA-PSS-SHA384", PK_PKIX1_RSA_PSS_OID, GNUTLS_SIGN_RSA_PSS_SHA384,
GNUTLS_PK_RSA_PSS,
GNUTLS_DIG_SHA384, {8, 5}},
{"RSA-PSS-SHA512", PK_PKIX1_RSA_PSS_OID, GNUTLS_SIGN_RSA_PSS_SHA512,
GNUTLS_PK_RSA_PSS,
GNUTLS_DIG_SHA512, {8, 6}},
{0, 0, 0, 0, 0, TLS_SIGN_AID_UNKNOWN}
};
#define GNUTLS_SIGN_LOOP(b) \
do { \
const gnutls_sign_entry *p; \
for(p = sign_algorithms; p->name != NULL; p++) { b ; } \
} while (0)
#define GNUTLS_SIGN_ALG_LOOP(a) \
GNUTLS_SIGN_LOOP( if(p->id && p->id == sign) { a; break; } )
/**
* gnutls_sign_get_name:
* @algorithm: is a sign algorithm
*
* Convert a #gnutls_sign_algorithm_t value to a string.
*
* Returns: a string that contains the name of the specified sign
* algorithm, or %NULL.
**/
const char *gnutls_sign_get_name(gnutls_sign_algorithm_t algorithm)
{
gnutls_sign_algorithm_t sign = algorithm;
const char *ret = NULL;
/* avoid prefix */
GNUTLS_SIGN_ALG_LOOP(ret = p->name);
return ret;
}
/**
* gnutls_sign_is_secure:
* @algorithm: is a sign algorithm
*
* Returns: Non-zero if the provided signature algorithm is considered to be secure.
**/
int gnutls_sign_is_secure(gnutls_sign_algorithm_t algorithm)
{
gnutls_sign_algorithm_t sign = algorithm;
gnutls_digest_algorithm_t dig = GNUTLS_DIG_UNKNOWN;
/* avoid prefix */
GNUTLS_SIGN_ALG_LOOP(dig = p->mac);
if (dig != GNUTLS_DIG_UNKNOWN)
return _gnutls_digest_is_secure(hash_to_entry(dig));
return 0;
}
/**
* gnutls_sign_list:
*
* Get a list of supported public key signature algorithms.
*
* Returns: a (0)-terminated list of #gnutls_sign_algorithm_t
* integers indicating the available ciphers.
*
**/
const gnutls_sign_algorithm_t *gnutls_sign_list(void)
{
static gnutls_sign_algorithm_t supported_sign[MAX_ALGOS] = { 0 };
if (supported_sign[0] == 0) {
int i = 0;
GNUTLS_SIGN_LOOP(supported_sign[i++] = p->id);
supported_sign[i++] = 0;
}
return supported_sign;
}
/**
* gnutls_sign_get_id:
* @name: is a sign algorithm name
*
* The names are compared in a case insensitive way.
*
* Returns: return a #gnutls_sign_algorithm_t value corresponding to
* the specified algorithm, or %GNUTLS_SIGN_UNKNOWN on error.
**/
gnutls_sign_algorithm_t gnutls_sign_get_id(const char *name)
{
gnutls_sign_algorithm_t ret = GNUTLS_SIGN_UNKNOWN;
GNUTLS_SIGN_LOOP(
if (strcasecmp(p->name, name) == 0) {
ret = p->id;
break;
}
);
return ret;
}
/**
* gnutls_oid_to_sign:
* @oid: is an object identifier
*
* Converts a textual object identifier to a #gnutls_sign_algorithm_t value.
*
* Returns: a #gnutls_sign_algorithm_t id of the specified digest
* algorithm, or %GNUTLS_SIGN_UNKNOWN on failure.
*
* Since: 3.4.3
**/
gnutls_sign_algorithm_t gnutls_oid_to_sign(const char *oid)
{
gnutls_sign_algorithm_t ret = 0;
GNUTLS_SIGN_LOOP(
if (p->oid && strcmp(oid, p->oid) == 0) {
ret = p->id; break;}
);
if (ret == 0) {
_gnutls_debug_log("Unknown SIGN OID: '%s'\n", oid);
return GNUTLS_SIGN_UNKNOWN;
}
return ret;
}
/**
* gnutls_pk_to_sign:
* @pk: is a public key algorithm
* @hash: a hash algorithm
*
* This function maps public key and hash algorithms combinations
* to signature algorithms.
*
* Returns: return a #gnutls_sign_algorithm_t value, or %GNUTLS_SIGN_UNKNOWN on error.
**/
gnutls_sign_algorithm_t
gnutls_pk_to_sign(gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash)
{
gnutls_sign_algorithm_t ret = 0;
GNUTLS_SIGN_LOOP(
if (pk == p->pk && hash == p->mac) {
ret = p->id;
break;
}
);
if (ret == 0)
return GNUTLS_SIGN_UNKNOWN;
return ret;
}
/**
* gnutls_sign_get_oid:
* @sign: is a sign algorithm
*
* Convert a #gnutls_sign_algorithm_t value to its object identifier.
*
* Returns: a string that contains the object identifier of the specified sign
* algorithm, or %NULL.
*
* Since: 3.4.3
**/
const char *gnutls_sign_get_oid(gnutls_sign_algorithm_t sign)
{
const char *ret = NULL;
GNUTLS_SIGN_ALG_LOOP(ret = p->oid);
return ret;
}
/**
* gnutls_sign_get_hash_algorithm:
* @sign: is a signature algorithm
*
* This function returns the digest algorithm corresponding to
* the given signature algorithms.
*
* Since: 3.1.1
*
* Returns: return a #gnutls_digest_algorithm_t value, or %GNUTLS_DIG_UNKNOWN on error.
**/
gnutls_digest_algorithm_t
gnutls_sign_get_hash_algorithm(gnutls_sign_algorithm_t sign)
{
gnutls_digest_algorithm_t ret = GNUTLS_DIG_UNKNOWN;
GNUTLS_SIGN_ALG_LOOP(ret = p->mac);
return ret;
}
/**
* gnutls_sign_get_pk_algorithm:
* @sign: is a signature algorithm
*
* This function returns the public key algorithm corresponding to
* the given signature algorithms.
*
* Since: 3.1.1
*
* Returns: return a #gnutls_pk_algorithm_t value, or %GNUTLS_PK_UNKNOWN on error.
**/
gnutls_pk_algorithm_t
gnutls_sign_get_pk_algorithm(gnutls_sign_algorithm_t sign)
{
gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
GNUTLS_SIGN_ALG_LOOP(ret = p->pk);
return ret;
}
gnutls_sign_algorithm_t
_gnutls_tls_aid_to_sign(const sign_algorithm_st * aid)
{
gnutls_sign_algorithm_t ret = GNUTLS_SIGN_UNKNOWN;
if (aid->hash_algorithm == unknown_tls_aid.hash_algorithm &&
aid->sign_algorithm == unknown_tls_aid.sign_algorithm)
return ret;
GNUTLS_SIGN_LOOP(
if (p->aid.hash_algorithm == aid->hash_algorithm &&
p->aid.sign_algorithm == aid->sign_algorithm) {
ret = p->id;
break;
}
);
return ret;
}
/* Returns NULL if a valid AID is not found
*/
const sign_algorithm_st *_gnutls_sign_to_tls_aid(gnutls_sign_algorithm_t
sign)
{
const sign_algorithm_st *ret = NULL;
GNUTLS_SIGN_ALG_LOOP(ret = &p->aid);
if (ret != NULL &&
ret->hash_algorithm == unknown_tls_aid.hash_algorithm &&
ret->sign_algorithm == unknown_tls_aid.sign_algorithm)
return NULL;
return ret;
}