it-swarm.com.ru

Как определить местоположение по умолчанию для openssl.cnf?

Фон

Я пишу bash-скрипт, который будет использовать openssl для генерации запроса на подпись сертификата с совместимость с расширением X509v3 альтернативными именами субъекта.

Поскольку для этого нет параметра командной строки, решение использовало параметр -config в сочетании с параметром -reqexts, добавляя значения SAN, встроенные в файл конфигурации по умолчанию.

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

Вопрос

Моя проблема в мобильности. Хотя аналогичный вопрос уверяет меня, что это работает в моей среде Ubuntu, потому что файл конфигурации по умолчанию - /etc/ssl/openssl.cnf, к сожалению, это не сработает везде, и очевидным примером является Windows.

Как мне программно определить полный путь к файлу конфигурации openssl default?

Что я пробовал

Есть явный намек в документации

-config имя файла
это позволяет указать альтернативный файл конфигурации, переопределяет имя файла времени компиляции или любое другое, указанное в переменной среды OPENSSL_CONF.

Я прочитал config документацию и искал исходный код , но я не могу обнаружить механизм, с помощью которого он выбирает, куда загружать файл конфигурации по умолчанию "время компиляции". Если бы я мог найти это, я бы предпочел загрузить его как переменную в сценарий, а не жестко закодированный путь.

Более того, моя переменная $OPENSSL_CONF пуста.

Плохая альтернатива

В настоящее время мой скрипт проверяет эти условия и использует первое, которое оценивается как true:

  1. переменная $OPENSSL_CONF заполнена, и файл существует
  2. /etc/ssl/openssl.cnf существует

Если ни один из них не соответствует действительности, то он включает в себя копию стандартной конфигурации. Это нежелательно, поскольку в действительности оно переопределяет пользовательские настройки, установленные клиентом. Я хочу полностью использовать условия среды и просто добавить раздел SAN в качестве дополнения.

Я мог бы дополнительно расширить эту цепочку путями обычных подозреваемых или даже системным поиском. Но если существует несколько, я не уверен, что по умолчанию используется openssl.

9
Jeff Puckett

Как программно определить полный путь к файлу конфигурации openssl по умолчанию?

Программно это так же просто, как использовать макрос OPENSSLDIR из 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"

Как определить местоположение по умолчанию для openssl.cnf?

Вот дополнительная информация, чтобы помочь заполнить пробелы в другом вопросе переполнения стека. Это зависит от используемой вами установки OpenSSL.

Вот краткий ответ ... Библиотека и программы ищут openssl.cnf в OPENSSLDIR. OPENSSLDIR - это опция настройки, которая устанавливается с помощью --openssldir.

Я нахожусь на MacBook с 3 различными OpenSSL (Apple, MacPort и тот, который я строю):

# 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"

Вот более длинный ответ ... Он как бы скрыт в исходном коде OpenSSL для apps.c, load_config и того, что происходит, когда cnf равен NULL (т.е. без опции -config или OPENSSL_CONF envar). Когда cnf равен NULL и не имеет переопределений, тогда используется OPENSSLDIR.

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;
}

... это работает в моей среде Ubuntu, потому что файл конфигурации по умолчанию - /etc/ssl/openssl.cnf, к сожалению, это не сработает повсюду, и очевидным примером является Windows.

Это все еще может быть проблемой для вас в Windows. Вы должны быть в порядке, если вы сами собираете OpenSSL из исходников; по модулю их обработки длинных имен файлов в Windows (также см. выпуск # 4490: «nmake install» завершается с ошибкой «Адресат должен быть каталогом в.\util\copy.pl line 39» on ).

Такие люди, как Shinning Light и Win32 OpenSSL предоставляют установщики, а OpenSSL не может быть установлен в каталог, который предусмотрел упаковщик. Я даже видел каталоги Unix, такие как /usr/local, на компьютерах с Windows.

Для Windows самая безопасная ставка - установить переменную окружения OPENSSL_CONF, чтобы переопределять ошибочные пути и ошибки обработки путей.


Кроме того, мне не известны вызовы API CONF_* или NCONF_*, которые дают эффективный каталог во время выполнения. Здесь эффективным каталогом будет каталог конфигурации плюс такие вещи, как OPENSSL_CONF переопределения. Теперь откройте в списке пользователей OpenSSL: Получить эффективный путь OPENSSLDIR во время выполнения?

6
jww

Как упомянуто в одном из комментариев, простой ответ должен состоять в том, чтобы найти путь, используя следующую команду:

openssl version -d

Если это не работает, вы можете предположить, что OpenSSL настроен неправильно или, по крайней мере, не имеет необходимой конфигурации. Вот пример в Node.js о том, как вы можете получить местоположение 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