web-dev-qa-db-fra.com

Comment déterminer l'emplacement par défaut de openssl.cnf?

Contexte

J'écris un script bash qui utilisera openssl pour générer une demande de signature de certificat avec conforme à l'extension X509v3 nom alternatif.

Comme il n'y a pas d'option de ligne de commande pour cela, une solution a été d'utiliser l'option -config conjointement avec l'option -reqexts en ajoutant les valeurs SAN au fichier de configuration par défaut.

openssl req -new -sha256 -key domain.key -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) -out domain.csr

Question

Mon problème est la portabilité. Bien que une question similaire m'assure que cela fonctionne dans mon environnement Ubuntu car le fichier de configuration par défaut est /etc/ssl/openssl.cnf, malheureusement, cela ne fonctionnera pas partout, Windows étant l'exemple le plus évident.

Comment je par programme détermine-t-il le chemin complet du fichier openssl default fichier de configuration?

Ce que j'ai essayé

Il y a un indice flagrant dans la documentation

-config nomfichier
Ceci permet de spécifier un autre fichier de configuration, il remplace le nom de fichier de la compilation ou tout autre élément spécifié dans la variable d'environnement OPENSSL_CONF.

J'ai lu la documentation config et recherché le code source , mais je ne peux pas découvrir le mécanisme par lequel il choisit l'endroit où charger le fichier de configuration par défaut "compile time". Si je pouvais le trouver, je préférerais alors le charger en tant que variable dans le script plutôt que le chemin codé en dur.

De plus, ma variable $OPENSSL_CONF est vide.

Une mauvaise alternative

Actuellement, mon script vérifie ces conditions et utilise le premier qui est évalué à true:

  1. La variable $OPENSSL_CONF est renseignée et le fichier existe
  2. /etc/ssl/openssl.cnf existe

Si aucune de celles-ci n'est vraie, cela inclut une copie d'une configuration standard. Cela n'est pas souhaitable car cela aurait pour effet de remplacer les paramètres personnalisés établis par le client. Je souhaite utiliser complètement les conditions de l'environnement et ajouter simplement la section SAN en tant qu'addenda.

Je pourrais encore étendre cette chaîne avec les chemins des suspects habituels ou même une recherche de système. Mais dans le cas où plusieurs existent, je n’ai aucune garantie quant à ce qui est en fait utilisé par openssl par défaut.

9
Jeff Puckett

Comment déterminer par programme le chemin d'accès complet au fichier de configuration par défaut openssl?

Par programme, c’est aussi simple que d’utiliser la macro OPENSSLDIR de opensslconf.h:

$ cat /usr/local/ssl/darwin/include/openssl/opensslconf.h | grep OPENSSLDIR
#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR)
#define OPENSSLDIR "/usr/local/ssl/darwin"

Comment déterminer l'emplacement par défaut de openssl.cnf?

Voici plus d'informations pour vous aider à combler les lacunes de l'autre question sur le dépassement de capacité. Cela dépend de l'installation OpenSSL que vous utilisez.

Voici la réponse courte ... La bibliothèque et les programmes recherchent openssl.cnf dans OPENSSLDIR. OPENSSLDIR est une option de configuration et est définie avec --openssldir.

Je suis sur un MacBook avec 3 OpenSSL différents (Apple, MacPort et celui que je construis):

# Apple    
$ /usr/bin/openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/System/Library/OpenSSL"

# MacPorts
$ /opt/local/bin/openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/opt/local/etc/openssl"

# My build of OpenSSL
$ openssl version -a | grep OPENSSLDIR
OPENSSLDIR: "/usr/local/ssl/darwin"

Voici la réponse la plus longue ... C'est un peu enfoui dans le code source OpenSSL pour apps.c, load_config et ce qui se produit lorsque cnf est NULL (c'est-à-dire, aucune option -config ou OPENSSL_CONF envar). Lorsque cnf est NULL et qu'il n'y a pas de substitution, alors OPENSSLDIR est utilisé.

int load_config(BIO *err, CONF *cnf)
{
    static int load_config_called = 0;
    if (load_config_called)
        return 1;
    load_config_called = 1;
    if (!cnf)
        cnf = config;
    if (!cnf)
        return 1;

    OPENSSL_load_builtin_modules();

    if (CONF_modules_load(cnf, NULL, 0) <= 0) {
        BIO_printf(err, "Error configuring OpenSSL\n");
        ERR_print_errors(err);
        return 0;
    }
    return 1;
}

... cela fonctionne dans mon environnement Ubuntu car le fichier de configuration par défaut est /etc/ssl/openssl.cnf; malheureusement, cela ne fonctionnera pas partout, Windows étant l'exemple le plus évident.

Cela peut toujours être un problème pour vous sous Windows. Vous devriez être OK si vous construisez OpenSSL à partir de sources vous-même; modulo leur gestion de nom de fichier long sous Windows (voir aussi Problème n ° 4490: "Installation de nmake" échoue "La destination doit être un répertoire situé à.\util\copy.pl ligne 39" sur ).

Des personnes comme Shinning Light et Win32 OpenSSL fournissent les programmes d'installation et OpenSSL ne peuvent pas être installées dans le répertoire que le gestionnaire de paquets a envisagé. J'ai même vu des répertoires Unix tels que /usr/local apparaître sur des machines Windows.

Pour Windows, votre pari le plus sûr est probablement de définir la variable d'environnement OPENSSL_CONF pour remplacer les chemins d'accès brisés et les bogues de traitement des chemins.


De plus, je ne suis pas au courant d'un appel d'API CONF_* ou NCONF_* qui vous donne le répertoire effectif au moment de l'exécution. Ici, le répertoire effectif serait le répertoire de configuration plus des choses telles que OPENSSL_CONF remplace. Ouvrez maintenant dans la liste des utilisateurs OpenSSL: Obtenir le chemin OPENSSLDIR effectif à l'exécution?

6
jww

Comme mentionné dans l'un des commentaires, la réponse simple devrait être de trouver le chemin à l'aide de la commande suivante:

openssl version -d

Si cela ne fonctionne pas, vous pouvez présumer qu'OpenSSL n'est pas configuré correctement ou du moins n'a pas la configuration dont vous avez besoin. Voici un exemple dans Node.js sur la façon dont vous pouvez obtenir l'emplacement de openssl.cnf:

const util = require('util');
const path = require('path');
const exec = util.promisify(require('child_process').exec);

(async () => {
    const opensslCnfPath = path.normalize(`${(await exec('openssl version -d')).stdout.match(/"(.*)"/).pop()}/openssl.cnf`);
    console.log(opensslCnfPath);
})();
1
Nicolas Bouvrette