Руководство по openssl

NAME

openssl — OpenSSL command line program

SYNOPSIS

openssl command [ options … ] [ parameters … ]

openssl no-XXX [ options ]

DESCRIPTION

OpenSSL is a cryptography toolkit implementing the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) network protocols and related cryptography standards required by them.

The openssl program is a command line program for using the various cryptography functions of OpenSSL’s crypto library from the shell. It can be used for

o  Creation and management of private keys, public keys and parameters
o  Public key cryptographic operations
o  Creation of X.509 certificates, CSRs and CRLs
o  Calculation of Message Digests and Message Authentication Codes
o  Encryption and Decryption with Ciphers
o  SSL/TLS Client and Server Tests
o  Handling of S/MIME signed or encrypted mail
o  Timestamp requests, generation and verification

COMMAND SUMMARY

The openssl program provides a rich variety of commands (command in the «SYNOPSIS» above). Each command can have many options and argument parameters, shown above as options and parameters.

Detailed documentation and use cases for most standard subcommands are available (e.g., openssl-x509(1)). The subcommand openssl-list(1) may be used to list subcommands.

The command no-XXX tests whether a command of the specified name is available. If no command named XXX exists, it returns 0 (success) and prints no-XXX; otherwise it returns 1 and prints XXX. In both cases, the output goes to stdout and nothing is printed to stderr. Additional command line arguments are always ignored. Since for each cipher there is a command of the same name, this provides an easy way for shell scripts to test for the availability of ciphers in the openssl program. (no-XXX is not able to detect pseudo-commands such as quit, list, or no-XXX itself.)

Configuration Option

Many commands use an external configuration file for some or all of their arguments and have a -config option to specify that file. The default name of the file is openssl.cnf in the default certificate storage area, which can be determined from the openssl-version(1) command using the -d or -a option. The environment variable OPENSSL_CONF can be used to specify a different file location or to disable loading a configuration (using the empty string).

Among others, the configuration file can be used to load modules and to specify parameters for generating certificates and random numbers. See config(5) for details.

Standard Commands

asn1parse

Parse an ASN.1 sequence.

ca

Certificate Authority (CA) Management.

ciphers

Cipher Suite Description Determination.

cms

CMS (Cryptographic Message Syntax) command.

crl

Certificate Revocation List (CRL) Management.

crl2pkcs7

CRL to PKCS#7 Conversion.

dgst

Message Digest calculation. MAC calculations are superseded by openssl-mac(1).

dhparam

Generation and Management of Diffie-Hellman Parameters. Superseded by openssl-genpkey(1) and openssl-pkeyparam(1).

dsa

DSA Data Management.

dsaparam

DSA Parameter Generation and Management. Superseded by openssl-genpkey(1) and openssl-pkeyparam(1).

ec

EC (Elliptic curve) key processing.

ecparam

EC parameter manipulation and generation.

enc

Encryption, decryption, and encoding.

engine

Engine (loadable module) information and manipulation.

errstr

Error Number to Error String Conversion.

fipsinstall

FIPS configuration installation.

gendsa

Generation of DSA Private Key from Parameters. Superseded by openssl-genpkey(1) and openssl-pkey(1).

genpkey

Generation of Private Key or Parameters.

genrsa

Generation of RSA Private Key. Superseded by openssl-genpkey(1).

help

Display information about a command’s options.

info

Display diverse information built into the OpenSSL libraries.

kdf

Key Derivation Functions.

list

List algorithms and features.

mac

Message Authentication Code Calculation.

nseq

Create or examine a Netscape certificate sequence.

ocsp

Online Certificate Status Protocol command.

passwd

Generation of hashed passwords.

pkcs12

PKCS#12 Data Management.

pkcs7

PKCS#7 Data Management.

pkcs8

PKCS#8 format private key conversion command.

pkey

Public and private key management.

pkeyparam

Public key algorithm parameter management.

pkeyutl

Public key algorithm cryptographic operation command.

prime

Compute prime numbers.

rand

Generate pseudo-random bytes.

rehash

Create symbolic links to certificate and CRL files named by the hash values.

req

PKCS#10 X.509 Certificate Signing Request (CSR) Management.

rsa

RSA key management.

rsautl

RSA command for signing, verification, encryption, and decryption. Superseded by openssl-pkeyutl(1).

s_client

This implements a generic SSL/TLS client which can establish a transparent connection to a remote server speaking SSL/TLS. It’s intended for testing purposes only and provides only rudimentary interface functionality but internally uses mostly all functionality of the OpenSSL ssl library.

s_server

This implements a generic SSL/TLS server which accepts connections from remote clients speaking SSL/TLS. It’s intended for testing purposes only and provides only rudimentary interface functionality but internally uses mostly all functionality of the OpenSSL ssl library. It provides both an own command line oriented protocol for testing SSL functions and a simple HTTP response facility to emulate an SSL/TLS-aware webserver.

s_time

SSL Connection Timer.

sess_id

SSL Session Data Management.

smime

S/MIME mail processing.

speed

Algorithm Speed Measurement.

spkac

SPKAC printing and generating command.

srp

Maintain SRP password file. This command is deprecated.

storeutl

Command to list and display certificates, keys, CRLs, etc.

ts

Time Stamping Authority command.

verify

X.509 Certificate Verification. See also the openssl-verification-options(1) manual page.

version

OpenSSL Version Information.

x509

X.509 Certificate Data Management.

Message Digest Commands

blake2b512

BLAKE2b-512 Digest

blake2s256

BLAKE2s-256 Digest

md2

MD2 Digest

md4

MD4 Digest

md5

MD5 Digest

mdc2

MDC2 Digest

rmd160

RMD-160 Digest

sha1

SHA-1 Digest

sha224

SHA-2 224 Digest

sha256

SHA-2 256 Digest

sha384

SHA-2 384 Digest

sha512

SHA-2 512 Digest

sha3-224

SHA-3 224 Digest

sha3-256

SHA-3 256 Digest

sha3-384

SHA-3 384 Digest

sha3-512

SHA-3 512 Digest

keccak-224

KECCAK 224 Digest

keccak-256

KECCAK 256 Digest

keccak-384

KECCAK 384 Digest

keccak-512

KECCAK 512 Digest

shake128

SHA-3 SHAKE128 Digest

shake256

SHA-3 SHAKE256 Digest

sm3

SM3 Digest

Encryption, Decryption, and Encoding Commands

The following aliases provide convenient access to the most used encodings and ciphers.

Depending on how OpenSSL was configured and built, not all ciphers listed here may be present. See openssl-enc(1) for more information.

aes128, aes-128-cbc, aes-128-cfb, aes-128-ctr, aes-128-ecb, aes-128-ofb

AES-128 Cipher

aes192, aes-192-cbc, aes-192-cfb, aes-192-ctr, aes-192-ecb, aes-192-ofb

AES-192 Cipher

aes256, aes-256-cbc, aes-256-cfb, aes-256-ctr, aes-256-ecb, aes-256-ofb

AES-256 Cipher

aria128, aria-128-cbc, aria-128-cfb, aria-128-ctr, aria-128-ecb, aria-128-ofb

Aria-128 Cipher

aria192, aria-192-cbc, aria-192-cfb, aria-192-ctr, aria-192-ecb, aria-192-ofb

Aria-192 Cipher

aria256, aria-256-cbc, aria-256-cfb, aria-256-ctr, aria-256-ecb, aria-256-ofb

Aria-256 Cipher

base64

Base64 Encoding

bf, bf-cbc, bf-cfb, bf-ecb, bf-ofb

Blowfish Cipher

camellia128, camellia-128-cbc, camellia-128-cfb, camellia-128-ctr, camellia-128-ecb, camellia-128-ofb

Camellia-128 Cipher

camellia192, camellia-192-cbc, camellia-192-cfb, camellia-192-ctr, camellia-192-ecb, camellia-192-ofb

Camellia-192 Cipher

camellia256, camellia-256-cbc, camellia-256-cfb, camellia-256-ctr, camellia-256-ecb, camellia-256-ofb

Camellia-256 Cipher

cast, cast-cbc

CAST Cipher

cast5-cbc, cast5-cfb, cast5-ecb, cast5-ofb

CAST5 Cipher

chacha20

Chacha20 Cipher

des, des-cbc, des-cfb, des-ecb, des-ede, des-ede-cbc, des-ede-cfb, des-ede-ofb, des-ofb

DES Cipher

des3, desx, des-ede3, des-ede3-cbc, des-ede3-cfb, des-ede3-ofb

Triple-DES Cipher

idea, idea-cbc, idea-cfb, idea-ecb, idea-ofb

IDEA Cipher

rc2, rc2-cbc, rc2-cfb, rc2-ecb, rc2-ofb

RC2 Cipher

rc4

RC4 Cipher

rc5, rc5-cbc, rc5-cfb, rc5-ecb, rc5-ofb

RC5 Cipher

seed, seed-cbc, seed-cfb, seed-ecb, seed-ofb

SEED Cipher

sm4, sm4-cbc, sm4-cfb, sm4-ctr, sm4-ecb, sm4-ofb

SM4 Cipher

OPTIONS

Details of which options are available depend on the specific command. This section describes some common options with common behavior.

Common Options

-help

Provides a terse summary of all options. If an option takes an argument, the «type» of argument is also given.

This terminates the list of options. It is mostly useful if any filename parameters start with a minus sign:

openssl verify [flags...] -- -cert1.pem...

Format Options

See openssl-format-options(1) for manual page.

Pass Phrase Options

See the openssl-passphrase-options(1) manual page.

Random State Options

Prior to OpenSSL 1.1.1, it was common for applications to store information about the state of the random-number generator in a file that was loaded at startup and rewritten upon exit. On modern operating systems, this is generally no longer necessary as OpenSSL will seed itself from a trusted entropy source provided by the operating system. These flags are still supported for special platforms or circumstances that might require them.

It is generally an error to use the same seed file more than once and every use of -rand should be paired with -writerand.

-rand files

A file or files containing random data used to seed the random number generator. Multiple files can be specified separated by an OS-dependent character. The separator is ; for MS-Windows, , for OpenVMS, and : for all others. Another way to specify multiple files is to repeat this flag with different filenames.

-writerand file

Writes the seed data to the specified file upon exit. This file can be used in a subsequent command invocation.

Certificate Verification Options

See the openssl-verification-options(1) manual page.

Name Format Options

See the openssl-namedisplay-options(1) manual page.

TLS Version Options

Several commands use SSL, TLS, or DTLS. By default, the commands use TLS and clients will offer the lowest and highest protocol version they support, and servers will pick the highest version that the client offers that is also supported by the server.

The options below can be used to limit which protocol versions are used, and whether TCP (SSL and TLS) or UDP (DTLS) is used. Note that not all protocols and flags may be available, depending on how OpenSSL was built.

-ssl3, -tls1, -tls1_1, -tls1_2, -tls1_3, -no_ssl3, -no_tls1, -no_tls1_1, -no_tls1_2, -no_tls1_3

These options require or disable the use of the specified SSL or TLS protocols. When a specific TLS version is required, only that version will be offered or accepted. Only one specific protocol can be given and it cannot be combined with any of the no_ options.

-dtls, -dtls1, -dtls1_2

These options specify to use DTLS instead of DLTS. With -dtls, clients will negotiate any supported DTLS protocol version. Use the -dtls1 or -dtls1_2 options to support only DTLS1.0 or DTLS1.2, respectively.

Engine Options

-engine id

Load the engine identified by id and use all the methods it implements (algorithms, key storage, etc.), unless specified otherwise in the command-specific documentation or it is configured to do so, as described in «Engine Configuration» in config(5).

The engine will be used for key ids specified with -key and similar options when an option like -keyform engine is given.

A special case is the loader_attic engine, which is meant just for internal OpenSSL testing purposes and supports loading keys, parameters, certificates, and CRLs from files. When this engine is used, files with such credentials are read via this engine. Using the file: schema is optional; a plain file (path) name will do.

Options specifying keys, like -key and similar, can use the generic OpenSSL engine key loading URI scheme org.openssl.engine: to retrieve private keys and public keys. The URI syntax is as follows, in simplified form:

org.openssl.engine:{engineid}:{keyid}

Where {engineid} is the identity/name of the engine, and {keyid} is a key identifier that’s acceptable by that engine. For example, when using an engine that interfaces against a PKCS#11 implementation, the generic key URI would be something like this (this happens to be an example for the PKCS#11 engine that’s part of OpenSC):

-key org.openssl.engine:pkcs11:label_some-private-key

As a third possibility, for engines and providers that have implemented their own OSSL_STORE_LOADER(3), org.openssl.engine: should not be necessary. For a PKCS#11 implementation that has implemented such a loader, the PKCS#11 URI as defined in RFC 7512 should be possible to use directly:

-key pkcs11:object=some-private-key;pin-value=1234

Provider Options

-provider name

Load and initialize the provider identified by name. The name can be also a path to the provider module. In that case the provider name will be the specified path and not just the provider module name. Interpretation of relative paths is platform specific. The configured «MODULESDIR» path, OPENSSL_MODULES environment variable, or the path specified by -provider-path is prepended to relative paths. See provider(7) for a more detailed description.

-provider-path path

Specifies the search path that is to be used for looking for providers. Equivalently, the OPENSSL_MODULES environment variable may be set.

-propquery propq

Specifies the property query clause to be used when fetching algorithms from the loaded providers. See property(7) for a more detailed description.

ENVIRONMENT

The OpenSSL library can be take some configuration parameters from the environment. Some of these variables are listed below. For information about specific commands, see openssl-engine(1), openssl-rehash(1), and tsget(1).

For information about the use of environment variables in configuration, see «ENVIRONMENT» in config(5).

For information about querying or specifying CPU architecture flags, see OPENSSL_ia32cap(3), and OPENSSL_s390xcap(3).

For information about all environment variables used by the OpenSSL libraries, see openssl-env(7).

OPENSSL_TRACE=name[,…]

Enable tracing output of OpenSSL library, by name. This output will only make sense if you know OpenSSL internals well. Also, it might not give you any output at all if OpenSSL was built without tracing support.

The value is a comma separated list of names, with the following available:

TRACE

Traces the OpenSSL trace API itself.

INIT

Traces OpenSSL library initialization and cleanup.

TLS

Traces the TLS/SSL protocol.

TLS_CIPHER

Traces the ciphers used by the TLS/SSL protocol.

CONF

Show details about provider and engine configuration.

ENGINE_TABLE

The function that is used by RSA, DSA (etc) code to select registered ENGINEs, cache defaults and functional references (etc), will generate debugging summaries.

ENGINE_REF_COUNT

Reference counts in the ENGINE structure will be monitored with a line of generated for each change.

PKCS5V2

Traces PKCS#5 v2 key generation.

PKCS12_KEYGEN

Traces PKCS#12 key generation.

PKCS12_DECRYPT

Traces PKCS#12 decryption.

X509V3_POLICY

Generates the complete policy tree at various points during X.509 v3 policy evaluation.

BN_CTX

Traces BIGNUM context operations.

CMP

Traces CMP client and server activity.

STORE

Traces STORE operations.

DECODER

Traces decoder operations.

ENCODER

Traces encoder operations.

REF_COUNT

Traces decrementing certain ASN.1 structure references.

HTTP

Traces the HTTP client and server, such as messages being sent and received.

SEE ALSO

openssl-asn1parse(1), openssl-ca(1), openssl-ciphers(1), openssl-cms(1), openssl-crl(1), openssl-crl2pkcs7(1), openssl-dgst(1), openssl-dhparam(1), openssl-dsa(1), openssl-dsaparam(1), openssl-ec(1), openssl-ecparam(1), openssl-enc(1), openssl-engine(1), openssl-errstr(1), openssl-gendsa(1), openssl-genpkey(1), openssl-genrsa(1), openssl-kdf(1), openssl-list(1), openssl-mac(1), openssl-nseq(1), openssl-ocsp(1), openssl-passwd(1), openssl-pkcs12(1), openssl-pkcs7(1), openssl-pkcs8(1), openssl-pkey(1), openssl-pkeyparam(1), openssl-pkeyutl(1), openssl-prime(1), openssl-rand(1), openssl-rehash(1), openssl-req(1), openssl-rsa(1), openssl-rsautl(1), openssl-s_client(1), openssl-s_server(1), openssl-s_time(1), openssl-sess_id(1), openssl-smime(1), openssl-speed(1), openssl-spkac(1), openssl-srp(1), openssl-storeutl(1), openssl-ts(1), openssl-verify(1), openssl-version(1), openssl-x509(1), config(5), crypto(7), openssl-env(7). ssl(7), x509v3_config(5)

HISTORY

The listXXX-algorithms options were added in OpenSSL 1.0.0; For notes on the availability of other commands, see their individual manual pages.

The -issuer_checks option is deprecated as of OpenSSL 1.1.0 and is silently ignored.

The -xcertform and -xkeyform options are obsolete since OpenSSL 3.0 and have no effect.

The interactive mode, which could be invoked by running openssl with no further arguments, was removed in OpenSSL 3.0, and running that program with no arguments is now equivalent to openssl help.

COPYRIGHT

Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the «License»). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at https://www.openssl.org/source/license.html.

Время на прочтение
14 мин

Количество просмотров 17K

Если вы искали руководство по криптографии, лежащей в основе OpenSSL, то вы оказались в правильном месте.

Эта статья является первой в серии из двух статей, посвященных основам криптографии, используемой в OpenSSL — библиотеке инструментов промышленного уровня, популярной и в среде Linux, и за ее пределами. (Чтобы установить самую последнюю версию OpenSSL, перейдите сюда.) Что касается взаимодействия с библиотекой, то вы можете вызывать ее функции из кода, а также в вашем распоряжении есть утилиты командной строки. Примеры кода для этой статьи приведены на C — на том же языке, на котором написана сама библиотека OpenSSL.

Две статьи этой серии в совокупности охватывают такие темы, как криптографические хеши, цифровые подписи, цифровые сертификаты, а также шифрование и дешифрование. Вы можете найти код и примеры для командной строки в ZIP-архиве на моем сайте.

Начнем же мы с обзора SSL, которому библиотека OpenSSL обязана своим именем (большей его части).

Краткая история

Secure Socket Layer (SSL, слой защищенных сокетов) — это криптографический протокол, выпущенный Netscape в 1995 году. Этот протокольный уровень может располагаться поверх HTTP, тем самым добавляя в конец букву S (HTTPS), которая означает secure. Протокол SSL предоставляет различные меры обеспечения безопасности, две из которых являются основополагающими в HTTPS:

  • Взаимная аутентификация (peer authentication, также известная как mutual challenge): каждая сторона соединения аутентифицирует идентификационные данные другой стороны. Если Алиса и Боб собираются обмениваться сообщениями через SSL, то сначала каждый должен аутентифицировать идентификационные данные своего собеседника.

  • Конфиденциальность: отправитель шифрует сообщения перед их отправкой по каналу связи. Затем получатель расшифровывает каждое полученное сообщение. Этот процесс защищает сетевое взаимодействие. Даже если злоумышленник Ева перехватит зашифрованное сообщение от Алисы к Бобу (атака через посредника), то она будет не в состоянии расшифровать это сообщение из-за необходимой для этого вычислительной сложности.

Эти две ключевые меры обеспечения безопасности SSL, в свою очередь, связаны с другими, которые зачастую остаются в тени. Например, SSL поддерживает целостность сообщений, что гарантирует, что полученное сообщение совпадает с отправленным. Эта фича реализована на основе хеш-функций, которые также входят в набор инструментов OpenSSL.

SSL имеет разные версии (например, SSLv2 и SSLv3), а в 1999 году на основе SSLv3 был реализован аналогичный протокол Transport Layer Security (TLS, протокол защиты транспортного уровня). TLSv1 и SSLv3 похожи, но не настолько, чтобы работать друг с другом. Тем не менее, принято называть SSL/TLS одним и тем же протоколом. Например, функции OpenSSL часто содержат SSL в имени, даже если используется TLS, а не SSL. Кроме того, вызов утилит командной строки OpenSSL начинается со строки openssl.

Документация по OpenSSL, к сожалению, достаточно неоднородна в своей полноте, особенно если смотреть за пределами справочных страниц (man pages), которые сами по себе достаточно громоздкие, учитывая, насколько велик инструментарий OpenSSL. В этой статье я  сфокусирую внимание на основных темах посредством примеров кода и командной строки. Начнем мы со знакомого всем нам примера — доступа к веб-сайту по HTTPS — и используем этот пример, чтобы разобрать основополагающие криптографические элементы.

HTTPS-клиент 

Приведенная ниже программа client подключается к Google по HTTPS:

/* компиляция: gcc -o client client.c -lssl -lcrypto */ 

#include <stdio.h>

#include <stdlib.h>

#include <openssl/bio.h> /* Базовые потоки ввода/вывода */

#include <openssl/err.h> /* ошибки */

#include <openssl/ssl.h> /* основная библиотека */

#define BuffSize 1024


void report_and_exit(const char* msg) {
  perror(msg);
  ERR_print_errors_fp(stderr);
  exit(-1);
}

 

void init_ssl() {
  SSL_load_error_strings();
  SSL_library_init();
}

 

void cleanup(SSL_CTX* ctx, BIO* bio) {
  SSL_CTX_free(ctx);
  BIO_free_all(bio);
}

 

void secure_connect(const char* hostname) {
  char name[BuffSize];
  char request[BuffSize];
  char response[BuffSize];

 

  const SSL_METHOD* method = TLSv1_2_client_method();
  if (NULL == method) report_and_exit("TLSv1_2_client_method...");

  SSL_CTX* ctx = SSL_CTX_new(method);
  if (NULL == ctx) report_and_exit("SSL_CTX_new...");

  BIO* bio = BIO_new_ssl_connect(ctx);
  if (NULL == bio) report_and_exit("BIO_new_ssl_connect...");

  SSL* ssl = NULL;

  /* связываем канал bio, сессию SSL и конечную точку сервера */

  sprintf(name, "%s:%s", hostname, "https");
  BIO_get_ssl(bio, &ssl); /* сессия */
  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* надежность */
  BIO_set_conn_hostname(bio, name); /* подготовка к подключению */

  /* пытаемся подключиться */
  if (BIO_do_connect(bio) <= 0) {
    cleanup(ctx, bio);
    report_and_exit("BIO_do_connect...");
  }


  /* проверяем хранилище доверенных сертификатов и сам сертификат */
  if (!SSL_CTX_load_verify_locations(ctx,
                                      "/etc/ssl/certs/ca-certificates.crt", /* хранилище доверенных сертификатов */


                                      "/etc/ssl/certs/")) /* больше доверенных сертификатов*/


    report_and_exit("SSL_CTX_load_verify_locations...");


  long verify_flag = SSL_get_verify_result(ssl);
  if (verify_flag != X509_V_OK)
    fprintf(stderr,
            "##### Certificate verification error (%i) but continuing...n",
            (int) verify_flag);

  /* теперь получаем домашнюю страницу в качестве проверочных данных */
  sprintf(request,
          "GET / HTTP/1.1x0Dx0AHost: %sx0Dx0Ax43onnection: Closex0Dx0Ax0Dx0A",
          hostname);
  BIO_puts(bio, request);
 

  /* читаем HTTP-ответ с сервера и выводим через stdout */
  while (1) {
    memset(response, '', sizeof(response));
    int n = BIO_read(bio, response, BuffSize);
    if (n <= 0) break; /* 0 — конец потока, < 0 — ошибка */


  puts(response);
  }


  cleanup(ctx, bio);
}


int main() {
  init_ssl();


  const char* hostname = "www.google.com:443";
  fprintf(stderr, "Trying an HTTPS connection to %s...n", hostname);
  secure_connect(hostname);

return 0;
}

(Прим. переводчика: этот код оказался нерабочим, исправленную версию можно посмотреть здесь)

Эту программу можно скомпилировать и запустить из командной строки (обратите внимание на строчную букву L в -lssl и -lcrypto):

gcc -o client client.c -lssl -lcrypto

Эта программа пытается установить безопасное соединение с сайтом www.google.com. В рамках TLS-рукопожатия с сервером Google программа-клиент получает один или несколько цифровых сертификатов, которые она затем пытается проверить (в моей системе они проверку не проходят). Тем не менее, далее программа-клиент получает по защищенному каналу домашнюю страницу Google. Эта программа полагается на упомянутые ранее артефакты безопасности, хотя в коде можно выделить только цифровой сертификат. Остальные же артефакты пока остаются за кадром, подробнее о них мы поговорим чуть дальше.

Как правило, программа-клиент на C или C++, которая открывает (незащищенный) HTTP-канал, будет использовать такой объект, как файловый дескриптор сетевого сокета, который является конечной точкой в ​​соединении между двумя процессами (например, программой-клиентом и сервером Google). Файловый дескриптор, в свою очередь, представляет собой неотрицательное целочисленное значение, которое идентифицирует внутри программы любую файловую конструкцию, которую эта программа открывает. Такой программе также понадобится структура для указания сведений об адресе сервера.

Ни один из этих относительно низкоуровневых объектов не встречается в программе-клиенте, поскольку библиотека OpenSSL заключает инфраструктуру сокетов и спецификацию адресов в высокоуровневые объекты безопасности. В результате мы получаем простой API. Вот какие процессы обеспечения безопасности мы можем увидеть в этом примере программы-клиента, не заглядывая под капот:

  • Программа начинается с загрузки необходимых библиотек OpenSSL, при этом моя функция init_ssl выполняет два вызова OpenSSL:

SSL_library_init(); SSL_load_error_strings();
  • Следующий шаг инициализации пытается получить контекст, информационную структуру, необходимую для установления и поддержания безопасного канала с сервером. В этом примере используется TLS1.2, что  мы можем увидеть в этом вызове функции из библиотеки OpenSSL:

const SSL_METHOD* method = TLSv1_2_client_method(); /* TLS 1.2 */

Если вызов выполнен успешно, то указатель method передается библиотечной функции, создающей контекст типа SSL_CTX:

SSL_CTX* ctx = SSL_CTX_new(method);

Программа-клиент проверяет наличие ошибок в каждом из этих критических библиотечных вызовов, а затем завершает работу, если какой-либо вызов завершается некорректно.

  • Теперь в игру вступают два других артефакта OpenSSL: сессия безопасности (security session) типа SSL, которая от начала и до конца управляет безопасным соединением; и защищенный поток типа BIO (базовый ввод/вывод), который используется для связи с сервером. Поток BIO создается с помощью следующего вызова:

BIO* bio = BIO_new_ssl_connect(ctx);

Обратите внимание, что аргументом является наша чрезвычайно важная переменная с контекстом. Тип BIO — это обертка OpenSSL для типа FILE в C. Эта обертка защищает потоки ввода/вывода между программой-клиентом и сервером Google.

  • Располагая SSL_CTX и BIO, программа затем связывает их вместе в сессии SSL. Эту работу выполняют три следующих библиотечных вызова:

BIO_get_ssl(bio, &ssl); /* получает сессию TLS */SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* для надежности */BIO_set_conn_hostname(bio, name); /* подготовка к соединению с Google */

Само безопасное соединение устанавливается с помощью этого вызова:

BIO_do_connect(bio);

Если этот последний вызов не увенчается успехом, программа-клиент завершает работу; в противном случае соединение готово для поддержки конфиденциального обмена данными между программой-клиентом и сервером Google.

Во время рукопожатия с сервером программа-клиент получает один или несколько цифровых сертификатов, удостоверяющих подлинность сервера. Однако программа-клиент не отправляет собственный сертификат, что означает одностороннюю аутентификацию. (Серверы обычно настроены не ожидать сертификата клиента.) Несмотря на неудачную проверку сертификата сервера, программа-клиент получает домашнюю страницу Google по безопасному каналу с сервером.

Почему проверка сертификата Google не заканчивается успехом? Типичная установка OpenSSL имеет каталог /etc/ssl/certs, который включает файл ca-certificates.crt. Каталог и файл содержат цифровые сертификаты, которым OpenSSL доверяет из коробки и, соответственно, составляют хранилище доверенных сертификатов (truststore). Хранилище доверенных сертификатов можно обновлять по мере необходимости, в частности, включать новые доверенные сертификаты и удалять ненадежные.

Программа-клиент получает три сертификата от сервера Google, но хранилище доверенных сертификатов OpenSSL на моей машине не содержит точных совпадений с ними. Как я в скором времени расскажу, программа-клиент не занимается, например, проверкой цифровой подписи на сертификате Google (подпись, подтверждающая сертификат). Если этой подписи доверяют, то сертификату, содержащему ее, также следует доверять. Тем не менее клиентская программа продолжает загрузку, а затем отображение домашней страницы Google. В следующем разделе мы рассмотрим это более подробно.

Скрытые механизмы безопасности в программе-клиенте

Начнем с артефакта безопасности, который мы видим в примере с клиентом — цифрового сертификата — и рассмотрим, как другие артефакты безопасности с ним связаны. Превалирующим стандартом структуры цифрового сертификата является X509, а сертификат производственного уровня выдаются центром сертификации (CA, certificate authority), таким как Verisign.

Цифровой сертификат содержит различную информацию (например, даты начала и истечения срока действия, а также доменное имя владельца), включая идентификационные данные издателя и цифровую подпись, которая представляет собой зашифрованное криптографическое хеш-значение. Сертификат также имеет незашифрованное хеш-значение, которое служит его идентифицирующим отпечаток (fingerprint).

Хеш-значение получается в результате сопоставления произвольного количества битов с хеш-суммой (digest) фиксированной длины. Что представляют собой биты (бухгалтерский отчет, роман или, может быть, фильм) не имеет значения. Например, хеш-алгоритм Message Digest версии 5 (MD5) отображает входные биты любой длины в 128-битное хеш-значение, тогда как алгоритм SHA1 (Secure Hash Algorithm версии 1) отображает входные биты в 160-битное значение. Различные входные биты приводят к разным — действительно, статистически уникальным — значениям хеш-функции. В следующей статье мы рассмотрим это более подробно и сосредоточимся на том, что именно делает хеш-функцию криптографической.

Цифровые сертификаты различаются по типу (например, корневой/root, промежуточный/intermediate и конечный/end-entity сертификаты) и образуют иерархию, отражающую эти типы. Как следует из названия, корневой сертификат находится на вершине иерархии, а сертификаты под ним наследуют любое доверие, которое имеет корневой сертификат. Библиотеки OpenSSL и большинство современных языков программирования имеют тип X509, как и функции, которые работают с такими сертификатами. Сертификат от Google имеет формат X509, и клиент проверяет, является ли этот сертификат X509_V_OK.

Сертификаты X509 основаны на инфраструктуре открытых ключей (PKI, public-key infrastructure), которая включает в себя алгоритмы (в основном доминирует RSA) для создания пар ключей: публичный ключ и его парный приватный ключ. Публичный ключ — это идентификационные данные (identity): публичный ключ Amazon идентифицирует его, а мой публичный ключ идентифицирует меня. Приватный ключ должен храниться его владельцем в секрете.

Ключи в паре имеют несколько стандартных применений. Публичный ключ можно использовать для шифрования сообщения, а приватный ключ из той же пары затем можно использовать для его расшифровки. Приватный ключ также можно использовать для подписи документа или другого электронного артефакта (например, программы или электронного письма), а затем публичный ключ из пары можно использовать для проверки этой подписи. Рассмотрим два примера.

В первом примере Алиса открывает свой публичный ключ всему миру, включая Боба. Затем Боб шифрует сообщение с помощью публичного ключа Алисы, отправляя ей зашифрованное сообщение. Сообщение, зашифрованное публичным ключом Алисы, расшифровывается ее приватным ключом, который (по идее) есть только у нее, вот так:

	           +------------------+ encrypted msg  +-------------------+
Bob's msg--->|Alice's public key|--------------->|Alice's private key|--->
Bob's msg
				     +------------------+                +-------------------+

Расшифровка сообщения без приватного ключа Алисы в принципе возможна, но на практике нереальна, учитывая надежность криптографической системы парных ключей, такой ​​как RSA.

Теперь в качестве второго примера рассмотрим подписание документа для подтверждения его подлинности. Алгоритм подписи использует приватный ключ из пары для обработки криптографического хеша подписываемого документа:

										+-------------------+
Hash of document--->|Alice's private key|--->Alice's digital signature of the document
										+-------------------+

Предположим, что Алиса подписывает цифровой подписью контракт, отправленный Бобу. Затем Боб может использовать публичный ключ Алисы для проверки подписи:

									             							 +------------------+
Alice's digital signature of the document--->|Alice's public key|--->verified or not
                                             +------------------+

Невозможно подделать подпись Алисы без ее приватного ключа: следовательно, в интересах Алисы сохранить ее приватный ключ в тайне.

Ни один из этих элементов безопасности, за исключением цифровых сертификатов, не является явным в нашей программе-клиенте. В следующей статье подробно описаны примеры, в которых используются утилиты OpenSSL и библиотечные функции.

OpenSSL из командной строки

А пока давайте взглянем на инструменты командной строки OpenSSL: в частности, утилиту для проверки сертификатов с сервера во время  TLS-рукопожатия. Вызов утилит OpenSSL начинается с команды openssl а затем добавляется комбинация аргументов и флагов для указания желаемой операции.

Рассмотрим эту команду:

openssl list-cipher-algorithms

Результатом является список связанных алгоритмов, составляющих набор шифров (cipher suite). Ниже приведено начало списка с комментариями для разъяснения аббревиатур:

AES-128-CBC ## Advanced Encryption Standard, Cipher Block Chaining
AES-128-CBC-HMAC-SHA1 ## Hash-based Message Authentication Code с хешами SHA1 
AES-128-CBC-HMAC-SHA256 ## тоже самое, но с SHA256 вместо SHA1
...

Следующая команда, используя аргумент s_client, открывает безопасное соединение с www.google.com и выводит на экран информацию об этом соединении:

openssl s_client -connect www.google.com:443 -showcerts

Номер порта 443 является стандартным, который используется серверами для приема соединений HTTPS, а не HTTP. (Для HTTP стандартный порт — 80). Сетевой адрес www.google.com:443 также встречается в программе-клиенте. Если попытка подключения успешна, отображаются три цифровых сертификата от Google вместе с информацией о безопасном сеансе, используемом наборе шифров и связанных элементах. Например, вот фрагмент начала вывода, который объявляет о предстоящей цепочке сертификатов. Кодировка сертификатов — base64:

Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
 i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
-----BEGIN CERTIFICATE-----
MIIEijCCA3KgAwIBAgIQdCea9tmy/T6rK/dDD1isujANBgkqhkiG9w0BAQsFADBU
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUw
...

Такие крупные сайты как Google, как правило, отправляют несколько сертификатов для аутентификации.

Выходные данные заканчиваются сводной информацией о сессии TLS, включая сведения о наборе шифров:

SSL-Session:
    Protocol : TLSv1.2
    Cipher : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: A2BBF0E4991E6BBBC318774EEE37CFCB23095CC7640FFC752448D07C7F438573
...

В программе-клиенте используется протокол TLS1.2, а Session-ID однозначно идентифицирует соединение между утилитой openssl и сервером Google. Запись Cipher может быть проанализирована следующим образом:

  • ECDHE (протокол Диффи-Хеллмана на эллиптических кривых) — эффективный и действенный алгоритм для управления TLS-рукопожатием. В частности, ECDHE решает проблему распределения ключей, гарантируя, что обе стороны соединения (например, программа-клиент и веб-сервер Google) используют один и тот же ключ шифрования/дешифрования, известный как ключ сессии (session key). Следующая часть серии детальнее раскроет эту тему.

  • RSA (Rivest Shamir Adleman) — доминирующая криптосистема с публичным ключом, названная в честь трех ученых, впервые описавших эту систему в конце 1970-х годов. Пары ключей генерируются с помощью алгоритма RSA.

  • AES128 (Advanced Encryption Standard) — это блочный шифр, который шифрует и расшифровывает блоки битов. (Альтернативой является потоковый шифр, который шифрует и расшифровывает биты по одному.) Шифр ​​является симметричным в том смысле, что для шифрования и дешифрования используется один и тот же ключ, что в первую очередь поднимает проблему распределения ключей. AES поддерживает размеры ключей 128 (используется здесь), 192 и 256 бит: чем больше ключ, тем лучше защита.

Размеры ключей для симметричных криптосистем, таких как AES, как правило, меньше, чем для асимметричных систем (на основе пары ключей), таких как RSA. Например, 1024-битный ключ RSA относительно мал, тогда как 256-битный ключ в настоящее время является самым большим для AES.

  • GCM (режим счетчика Галуа) обрабатывает повторное применение шифра (в данном случае AES128) во время защищенного общения. Блоки AES128 имеют размер всего 128 бит, и безопасный обмен данными, скорее всего, будет состоять из нескольких блоков AES128 от одной стороны к другой. GCM эффективен и обычно сочетается с AES128.

  • SHA256 (Secure Hash Algorithm с 256 бит) — это популярный криптографический алгоритм хеширования. Создаваемые хеш-значения имеют размер 256 бит, хотя с помощью SHA возможны и большие значения.

Наборы шифров находятся в постоянном развитии. Не так давно, например, Google использовала потоковый шифр RC4 (Ron’s Cipher версии 4 в честь Рона Ривеста из RSA). В RC4 теперь онаружены уязвимости, которые предположительно частично объясняют переход Google на AES128.

Подытожим

Это знакомство с OpenSSL посредством разбора безопасного веб-клиента C и различных примеров для командной строки выдвинуло на передний план несколько тем, нуждающихся в дополнительных пояснениях. Следующая статья посвящена деталям, начиная с криптографических хешей и заканчивая более полным обсуждением того, как цифровые сертификаты решают проблему распространения ключей.


Приглашаем всех желающих на открытое занятие «Встраиваем интерпретатор в приложение на C». На этом открытом уроке мы рассмотрим встраивание интерпретатора и виртуальной машины языка программирования высокого уровня в программу на C на примере скриптового языка Lua. Регистрируйтесь по ссылке.

OpenSSL — это система защиты и сертификации данных, название SSL переводится, как система безопасных сокетов (secure socket layer). OpenSSL используется практически всеми сетевыми серверами для защиты передаваемой информацией.

OpenSSL — это система защиты и сертификации данных, название SSL переводится, как система безопасных сокетов (secure socket layer). OpenSSL используется практически всеми сетевыми серверами для защиты передаваемой информацией. Существует программное API SSL (SSLEAY), позволяющее создавать безопасные сокеты с шифрацией передаваемых данных в собственных разработках. Но в данной статье я бы хотел рассказать о самой системе OpenSSL, вызываемой через командную строку.

Т.к. OpenSSL поддерживает очень много различных стандартов сертификации, шифрования, хеширования, то использование данной команды достаточно сложно. Внутри OpenSSL существуют отдельные компоненты, отвечающие за то или иное действие, для получения списка доступных компонентов можно вызвать openssl с параметрами list-standart-commands. Можно также получить список доступных алгоритмов хеширования (list-message-digest-commands) и алгоритмов шифрования (list-cipher-commands).

OpenSSL может использоваться во множестве случаев и умеет выполнять следующие задачи:

  • создавать и управлять ключами RSA и DSA — команды rsa, dsa, dsaparam;
  • создавать сертификаты формата x509, запросы на сертификацию, восстановление — команды x509, req, verify, ca, crl, pks12, pks7;
  • зашифровывать данные с помощью симметрического или асимметрического шифрования — команды enc, rsautl;
  • высчитывать хеши различных типов — команда dgst;
  • работать с S/MIME — команда s/mime;
  • проверять работу серверов и клиентов ssl — команды s_client, s_server.

Cуществует также несколько вспомогательных утилит ssl:

  • openssl speed [список_алгоритмов_хеширования_или шифрования]: тестирование скорости различных алгоритмов, если запускать без параметров, то тестируются все алгоритмы; алгоритмы внутри списка разделяются пробелом, например: openssl speed md5 rsa idea blowfish des 3des sha1. В конце работы выводится общая скорость работы различных алгоритмов (в 1000-х байт в секунду), для обработки различной длины блоков. Вот результат работы тестов скорости на моем домашнем компьютере (Celeron 366), на других машинах значения будут другими:
    Алгоритм           8 байт       64 байта     256 байт     1024 байта   8192 байт
    md2                291.38k      817.15k     1109.67k     1218.56k     1256.11k
    mdc2               868.57k      911.02k      914.01k      915.11k      917.50k
    md4               4417.91k    24808.28k    51404.97k    70189.40k    78168.06k
    md5               3905.61k    21142.91k    41515.69k    55489.54k    59091.63k
    hmac(md5)         1536.42k    10381.81k    27585.13k    46119.35k    57671.68k
    sha1              2458.59k    11965.97k    21560.58k    26889.22k    29143.66k
    rmd160            2032.99k     9523.48k    16568.15k    20547.81k    22220.11k
    rc4              28775.08k    39239.02k    41210.52k    41862.98k    41454.25k
    des cbc           7586.90k     8411.44k     8580.28k     8627.29k     8612.52k
    des ede3          2866.13k     3031.96k     3050.92k     3074.74k     3058.35k
    idea cbc          4948.09k     5743.19k     5760.09k     5744.67k     5723.48k
    rc2 cbc           2982.04k     3220.39k     3256.32k     3263.49k     3268.61k
    rc5-32/12 cbc    19108.39k    24151.19k    24906.75k    25154.90k    25212.25k
    blowfish cbc     11018.91k    12881.27k    12925.01k    12972.37k    13047.13k
    cast cbc         10943.48k    12674.30k    12877.74k    12994.56k    13011.63k
    

    Проверка алгоритмов асимметрического шифрования:

               Подписывание Проверка    За секунду подп. За секунду пров.
    rsa  512 bits   0.0036s   0.0003s    281.4           3221.7
    rsa 1024 bits   0.0184s   0.0009s     54.3           1072.9
    rsa 2048 bits   0.1105s   0.0032s      9.0            315.6
    rsa 4096 bits   0.7414s   0.0112s      1.3             89.4
    dsa 512 bits 0.0032s 0.0038s 311.3 261.3 dsa 1024 bits 0.0093s 0.0116s 107.5 86.4 dsa 2048 bits 0.0309s 0.0377s 32.4 26.5
  • openssl rand [-out file] [-rand file] num: генерация num рандомных байт, можно использовать для проверки рандомизационной последовательности rand:
    # openssl rand -rand .rnd 5
    Wеб~
    #
    
  • openssl ciphers [-ssl2] [-ssl3] [-tls1] NAME: вывод доступных алгоритмов для обеспечения уровня безопасности NAME, где NAME — это символическое название группы алгоритмов. Обычно используются значения:
    •   LOW — алгоритмы низкого уровня безопасности (<128 бит);
    •   MEDIUM — алгоритмы среднего уровня стойкости (128 бит);
    •   HIGH — алгоритмы высокой стойкости (>128 бит);
    •   ALL — все алгоритмы;
    •   NULL — алгоритмы без шифрования.

    Обычно в настоящее время используются алгоритмы групп MEDIUM и HIGH, которые еще долго не смогут быть взломаны прямым перебором. Можно также вывести список алгоритмов из нескольких групп, разделив их «:» (например, MEDIUM:HIGH).

Теперь я бы хотел рассказать об основных утилитах openssl. Для начала о методах генерации ключей, затем о командах шифрования, и, наконец, о сертификатах, s/mime. Итак, пару слов о генерации ключей. Для создания rsa-ключей используется команда genrsa:

openssl genrsa [-out file] [-des | -des3 | -idea] [-rand file] [bits]

Команда genrsa создает секретный ключ длиной bits в формате PEM, шифрует его одним из алгоритмов: des (56 бит), des3 (3-й des 168 бит) или idea (128 бит). При выборе алгоритма шифрования будет запрошен пароль для шифрации создаваемого секретного ключа (если алгоритм не указан, то секретный ключ не шифруется, чего делать ни в коем случае нельзя для личных ключей, т.к. некоторые серверы требуют отсутствие шифрации для сектетного ключа сервера). Опция -out говорит программе, что вывод нужно осуществлять не в stdout, а в файл file (опция -out присутствует во множестве других компонентов openssl и используется аналогичным образом для указания выходного файла). Опция -rand указывает на файл[ы] (разделенные «:»), из которых будут считываться данные для установки seed (зерна) генератора случайных чисел. В качестве таких файлов сразу же приходит на ум использовать что-то вроде /dev/random или /dev/urandom, но у меня с этим возникли проблемы: все вешалось наглухо, поэтому я рекомендую в этом случае использовать какие-нибудь сложно угадываемые файлы, вроде /var/log/messages или /boot/vmlinuz, думаю, что угадать содержимое этих файлов не намного проще, чем содержимое /dev/random, но работает этот фокус в любом *nix (опция -rand также присутствует во всех компонентах генерации и управления ключами и сертификатами). Использовать /dev/random и /dev/urandom, конечно, можно, но я для этого скопировал из /dev/random 32768 байт в файл .rnd таким образом:

dd if=/dev/[u]random of=.rnd count=64

Кроме этого, можно указывать в качестве -rand-файла EGD-сокет, который обеспечивает генерацию определенного количества случайных байт, EGD доступен на узле http://www.lothar.com/tech/crypto/. Установка генератора случайных чисел производится на основании хеша -rand файла, поэтому можно указывать файлы различной длины, т.к. хеш все равно имеет фиксированное число бит. Пример генерации 4096 битового секретного ключа RSA:

# openssl genrsa -out /etc/openssl/key.pem -des3 -rand /var/log/messages 4096
Generating RSA private key
.....++*...++++++++*
Enter PEM passphrase:
Verify PEM passphrase: 

После этого секретный ключ зашифровывается и записывается в файл (в текстовом виде). В начале ключа указывается алгоритм шифрования. Для создания публичного ключа rsa на основе секретного используется команда openssl rsa. Даная команда имеет следующий формат:

openssl rsa -in filename [-out file] [-des | -des3 |-idea] [-check] [-pubout]

Утилита openssl rsa способна изменять пароль и алгоритм шифрования секретного ключа, будучи вызвана с параметром -in и -out. Если применить параметр -pubout, то в указанный файл -out будет записан публичный ключ, вычисленный на основе -in секретного. Например, создание публичного ключа на основании секретного:

openssl rsa -in /etc/openssl/key.pem -out /etc/openssl/pubkey.pem -pubout

Изменение пароля и алгоритма шифрования секретного ключа с des3 на idea:

openssl rsa -in /etc/openssl/key.pem -out /etc/openssl/key1.pem -idea

Для создания ключей DSA используется утилита openssl gendsa, аналогичная genrsa, но есть два отличия: во-первых, для ключей DSA нельзя прямо указывать длину в битах и, во-вторых, ключи DSA могут генерироваться согласно некоторым параметрам, записанным в файл paramfile утилитой openssl dsaparam. dsaparam имеет следующий формат:

openssl dsaparam [-rand file{s}] [-C] [-genkey] [-out file]  numbits

где numbits — длина желаемого ключа, -С заставляет dsaparam вывести на stdout код на СИ для программной генерации DSA на основе необходимых параметров, а опция -genkey говорит, что в выходной файл, наряду с параметрами, дополнительно записывается созданный секретный ключ DSA, но нельзя его сразу же зашифровать, поэтому удобнее воспользоваться утилитой openssl gendsa, которая имеет схожий синтаксис с командой genrsa, но вместо числа бит указывается файл параметров, созданный dsaparam:

# openssl gendsa -out /etc/openssl/dsakey.pem -rand /boot/vmlinuz -idea paramfile
Enter PEM passphrase:
Verify PEM passphrase:

Для управления ключами dsa используется программа openssl dsa, которая абсолютно аналогична (в параметрах) утилите openssl rsa. Поэтому я просто приведу пример генерации публичного ключа DSA:

# openssl dsa -in /etc/openssl/dsakey.pem -out /etc/openssl/pubdsakey.pem -pubout

Теперь настало время рассказать о компонентах openssl, выполняющих шифрование и хеширование данных. Для выполнения симметрического шифрования используется утилита openssl enc -cipher или ее сокращенная запись openssl cipher, где cipher — это одно из символических имен симметрических шифров. Наиболее популярными являются следующие: base-64 (преобразование в текстовый вид), bf (blowfish — 128 бит), des (56 бит), des3 (168 бит), rc4 (128 бит), rc5 (128 бит), rc2 и idea (128 бит). Для указания входного и выходного файлов используется опции -in и -out соответственно. Пароль для шифрования вводится с клавиатуры (можно указать в командной строке параметром -k, но это очень плохо по соображениям безопасности, т.к. большинство шеллов умеют сохранять историю командной строки, IMHO намного лучше ввести пароль непосредственно перед шифрованием, хотя эта опция полезна для скриптов, так что забывать о ней нельзя :). Учтите, что пароль не спрашивается при обработке файла base64, т.к. шифрования не происходит. Для расшифровки зашифрованных данных примените openssl cipher с опцией -d (алгоритм шифрования и дешифрования должен совпадать!), а для одновременной обработки данных base64 можно воспользоваться опцией -a. Шифрование по умолчанию происходит с подмешиванием, т.е. для выбора алгоритма подмешивания используется случайная соль (salt), в этом случае, если вы шифруете один и тот же файл в разное время одним и тем же алгоритмом и паролем, то результаты скорее всего будут разными (это затрудняет атаку по словарю). Также по умолчанию используется cbc-режим алгоритмов, когда ключ меняется в течение всего сеанса работы согласно передаваемым данным, этот прием очень сильно затрудняет брутфорс, т.к. атакующему сложно поймать нужный момент времени. Приведу несколько примеров:

  • Зашифруем файл, используя алгоритм des3:
    # openssl des3 -in file -out file.des3
    
  • Расшифруем полученный файл:
    # openssl des3 -d -in file.des3 -out file
    
  • Зашифруем файл, используя алгоритм blowfish(bf), и закодируем base64:
    # openssl bf -a -in file -out file.bf64
    
  • Расшифруем его и обработаем сразу же base64:
    # openssl bf -a -d -in file.bf64 -out file
    

Для вычисления хешей (их еще называют отпечатками или контрольными суммами) используется команда openssl dgst -hashalg или краткая форма openssl hashalg (первая команда может также выполнять манипуляции с ЭЦП, но об этом далее). Обычное использование данной команды таково:

openssl hashalg [-c] file[s]

Вычисляется хеш-сообщения фиксированной длины в виде одной строки или, если указана опция -c, строки, разделенной на пары HEX-чисел двоеточием. Из алгоритмов хеширования могут применяться следующие: md2 (128 бит), md4(128 бит), md5 (128 бит), mdc2 (128 бит), sha (160 бит), sha1 (160 бит), ripemd160 (160 бит). Опять же приведу пару примеров:

  • Вычислим MD5-хеш файла:
    # openssl md5 -c file
    MD5(file)= 81:fd:20:ff:db:06:d5:2d:c3:55:b5:7d:3f:37:ac:94
    
  • И SHA1-хеш этого же файла:
    # openssl sha1 file
    SHA1(file)= 13f2b3abd8a7add2f3025d89593a0327a8eb83af
    

Как я уже говорил, утилита openssl dgst может использоваться для подписывания сообщения секретным ключом и проверки ЭЦП публичным ключом. Для этого используется следующий синтаксис:

openssl dgst -sign private_key -out signature -hashalg file[s]

Подписывание file с помощью секретного ключа «private_key», используя алгоритм хеширования «hasalg» (обычно применяются sha1 или md5).

openssl dgst -signature signature -verify public_key file[s]

Проверка подписи в «file», используя публичный ключ «public_key» и ЭЦП «signature». Данная программа выводит «Verification OK» при правильной подписи или «Verification Failure» в любом другом случае. Учтите, что ЭЦП в таком случае хранится отдельно от файла, который ею подписан (причем в каком-то кривом формате).

Для шифрации и дешифрации RSA алгоритмом используется программа rsautl. Данная утилита имеет также возможность подписывать и проверять подпись сообщений (однако работать все равно приходится с хешем сообщения, т.к. подписывать можно только небольшой объем данных, по этой причине лучше применять openssl dgst). Для шифрации/дешифрации используется следующий синтаксис:

openssl rsautl -in file -out file.cr -keyin pubkey.pem -pubin -encrypt

(Шифрация file с использованием публичного ключа pubkey.pem.)

openssl rsautl -in file.cr -out file -keyin secretkey.pem -decrypt

(Дешифрация file.cr с использованием секретного ключа secretkey.pem.)

Теперь настало время рассказать об одном из главных применений openssl — управление сертификатами. OpenSSL имеет возможность генерировать сертификаты, управлять ЭЦП и шифрацией с помощью сертификатов. Однако применение утилит управления сертификатами — достаточно сложная задача. Поэтому для начала я дам общие представления о сертификатах. Сертификат содержит публичный ключ, подписанный одним из корневых доверенных центров сертификации (или комплементарным секретным ключом), данные об организации, выдавшей сертификат и в некоторых случаях зашифрованный секретный ключ, а также отпечаток (хеш) публичного ключа. Сертификаты имеют время действия, по окончанию которого они автоматически считаются недействительными, иерархия сертификатов обычно строится на основании сети доверия (бывают довольно длинные цепочки сертификатов, ведущие к доверенному ключу из root CA). Таким образом, сертификат — это полный комплекс системы асимметрического шифрования, предоставляющий гораздо больше возможностей, чем сами по себе ключи (а также являющийся более защищенной системой). Основным привлекательным моментом сертификата является возможность записи в него информации об организации, этот ключ выдавшей. Таким образом, явно напрашивается применение собственной системы сертификации в данной организации. Можно, например, выдавать сотрудникам их персональные сертификаты, подписанные сертификатом организации (его можно сгенерировать самому или получить от сторонней компании). Причем эти сертификаты впоследствии можно использовать для удостоверения личности сотрудника, например, при почтовой переписке или аутентификации на http-сервере (apache+ssl). Единственное условие, которое должно выполняться, — это наличие на машине клиента сертификата организации в списке корневых доверенных ключей. Общее содержание сертификатов определено стандартом x509, в то время как форматы записей сертификатов могут внести некоторую путаницу. Openssl по умолчанию использует формат PKCS#10, Microsoft использует по умолчанию формат PKCS#12 (в руководстве по openssl этот формат охарактеризован, как один большой баг :), формат PKCS#7 используется для запросов на сертификацию к CA (центр сертификации) и не может содержать секретного ключа, также для этой цели может использоваться DER-закодированный сертификат (DER-кодирование подобно кодированию base64, но имеет специальное назначение для использования в криптографических системах) также без секретного ключа. Учтите, что при использовании DER-формата убираются маркеры начала и конца сертификата, а его содержимое кодируется base64, поэтому в файле DER можно хранить только один сертификат, с другой стороны DER сертификаты поддерживаются M$ (стандартное расширение .cer), поэтому иногда бывает нужно преобразовать сертификаты из одного формата в другой (я здесь имею в виду PEM или DER):

PEM-->DER openssl x509 -inform PEM -in cert.pem -outform DER -out cert.cer
DER-->PEM openssl x509 -inform DER -in cert.cer -outform PEM -out cert.pem

Таким же образом можно конвертировать и ключи асимметрического шифрования (используя утилиты rsa или dsa).

Думаю, что не сильно запутал вас всеми этими стандартами. Если объяснять на пальцах, то все выглядит следующим образом: клиент создает сертификат и отправляет свой публичный сертификат (PKCS#7) в центр сертификации. В центре сертификации обрабатывается запрос клиента (запрос на сертификацию), и сертификат клиента подписывается секретным ключом центра сертификации. Клиент, имея публичный ключ центра сертификации, проверяет подлинность подписи и может далее использовать свой сертификат. Для организации можно предложить следующее решение: на сервере создается сертификат организации; генерируется запрос на сертификацию и отправляется к некоему доверенному центру сертификации (который будет известен всем клиентам и персоналу данной организации); получается сертификат организации, который можно использовать при создании сертификатов клиентов. Последние создаются так: клиент посылает запрос на выдачу сертификата; сервер создает сертификат клиента и подписывает его сертификатом организации; клиент получает сертификат клиента и сертификат организации; после проверки достоверности ключа организации (предполагается, что клиент доверяет CA, которым был подписан сертификат организации) проверяется достоверность сертификата клиента. После такой операции клиент будет точно уверен, что получил сертификат от данной организации, и может его использовать для работы с ней. По такой схеме построены все центры выдачи сертификатов (правда, зачастую сертификат организации бывает подписан самим собой, что требует от клиента добавить сертификат организации к доверенным, а в первой схеме сертификат организации принадлежит к группе промежуточных центров сертификации, и этот случай предпочтительнее с точки зрения безопасности и удобства клиента, но требует больше работы от администратора). Да, хорошенькое объяснение на пальцах! Но что тут поделать: сертификаты — это довольно запутанная вещь. Сейчас я объясню, как создавать сертификаты с помощью openssl, и приведу пример только что описанного безобразия…

Для создания сертификата используется инструмент openssl req. Он имеет довольно много параметров, поэтому, чтобы не парить мозги, я просто приведу пару примеров его использования. Для начала требуется конфигурационный файл, который имеет следующий формат(все строки, начинающиеся с # — это мои комментарии, в конечном файле их может и не быть):

[ req ]
# Секция основных опций
default_bits           = 2048
# Число бит
default_keyfile        = keyfile.pem
# Имя ключа, используемого для сертификата
distinguished_name     = req_distinguished_name
# DN организации, выдавшей сертификат
prompt                 = no
# Брать параметры из конфига неинтерактивный режим
[ req_distinguished_name ]
# DN организации
CN=RU
# Страна
ST=Ivanovskaya
# Область
L=Gadukino
# Город
O=Krutie parni
# Название организации
OU=Sysopka
# Название отделения
CN=Your personal certificate
# Имя для сертификата (персоны, получающей сертификат)
emailAddress=certificate@gaduk.ru
# Мыло организации

Если не указывать prompt no, то значения для параметров будут считаны в интерактивном режиме (то бишь с клавиатуры), а значения параметров будут являться подсказками при вводе данных. При интерактивном режиме можно указывать значения по умолчанию, а также минимальное и максимальное значения для параметров (для строковых параметров устанавливается ограничение на длину). В таком случае общий формат параметра таков:

имя = подсказка
имя_default = значение_по_умолчанию
имя_max = максимум
имя_min = минимум

Пример интерактивного файла конфигурации:

[ req ]
default_bits           = 1024
default_keyfile        = privkey.pem
distinguished_name     = req_distinguished_name
[ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = RU countryName_min = 2 countryName_max = 2
localityName = Locality Name (eg, city) organizationName = Organization Name(eg, org) organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg, YOUR name) commonName_max = 64
emailAddress = Email Address emailAddress_max = 40

Спешу обрадовать некоторых ленивых товарищей: если вы намереваетесь создавать просто сертификат сервера (например, для LDAP-сервера), то указывать конфиг необязательно, будет использоваться конфиг по умолчанию /usr/lib/ssl/openssl.cnf, который содержит все необходимое. Ну а теперь традиционно приведу примеры использования openssl req(я не собираюсь подробно описывать данную команду, т.к. думаю, что для большинства случаев хватит примеров, а для особых случаев можно почитать man req).

openssl req -new -newkey rsa:2048 -keyout rsa_key.pem -config cfg -out certreq.pem

Создание запроса на сертификацию (-new) на основе создаваемого секретного ключа rsa (-newkey rsa:2048), который записывается в файл -keyout(и шифруется тройным DES). Запрос на сертификацию создается на основе конфигурационного файла — config.

openssl req -x509 -new -key private_key.pem -config cfg -out selfcert.pem -days 365

Создание (-new) self-signed сертификата (-x509) для использования в качестве сертификата сервера или сертификата CA. Сертификат создается с использованием секретного ключа -key и конфигурационного файла -config. Создаваемый сертификат будет действителен в течение 365 дней (-days), опция -days не применима к запросам на сертификацию.

Для управления сертификатами x509 используется утилита openssl x509. С ее помощью можно подписать сертификат или запрос на сертификацию сертификатом CA. Также можно просмотреть содержимое сертификата в читаемой форме (DN, публичный ключ, время действия, отпечаток и т.д.). Приведу примеры вышеописанных действий:

openssl x509 -in cert.pem -noout -text

Просмотреть информацию о сертификате в «нормальной» форме. Вот что примерно будет выведено, также можно использовать дополнительные опции: -fingerprint (необходимо сочетать с одной из опций -sha1, -md5 или -mdc2), -modulus (вывод публичного ключа), -serial, -subject, -issuer (организация, выдавшая сертификат), -email, -startdate, -enddate:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 0 (0x0)
        Signature Algorithm: md5WithRSAEncryption
        Issuer: C=RU, ST=region, L=city, O=organization, OU=Sysopka,
 CN=CEBKA/Email=CEBKA@smtp.ru
        Validity
            Not Before: Nov  9 08:51:03 2002 GMT
            Not After : Nov  9 08:51:03 2003 GMT
        Subject: C=RU, ST=region, L=city, O=organization, OU=Sysopka,
 CN=CEBKA/Email=CEBKA@smtp.ru
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:c6:6b:3b:8e:f8:33:05:a0:dc:e1:38:8f:6a:68:
                    42:1c:21:33:aa:90:b6:8c:93:14:11:9b:69:94:8a:
                    3a:0e:42:29:b0:45:14:1b:f0:37:2c:f3:05:db:13:
                    06:a9:cd:eb:99:31:51:25:86:c8:69:e0:5e:8d:28:
                    04:8d:1f:08:37:d7:72:39:fe:05:57:61:68:95:bf:
                    5c:ae:13:f2:05:a1:29:c3:bf:3b:32:ca:1a:ff:22:
                    53:f9:32:92:78:fe:44:c3:e1:ca:42:5c:5f:d1:49:
                    da:1c:9f:34:06:04:ee:46:74:8d:11:68:ef:37:e2:
                    74:1e:d9:46:04:b8:7e:d5:c5
                Exponent: 65537 (0x10001)
        Signature Algorithm: md5WithRSAEncryption
        3b:42:85:45:08:95:f3:f1:fc:8a:23:88:58:0e:be:e5:9b:56:
        1e:c1:ff:39:28:4f:84:19:f8:3e:38:ef:98:34:d6:ee:e0:0a:
        de:36:3a:5c:15:88:d7:2a:a4:0a:d5:dc:3e:b2:72:4c:82:57:
        b8:fe:52:f6:e2:06:01:38:eb:00:0b:f2:a9:87:be:65:83:19:
        13:50:ae:6c:f2:0a:07:14:e6:8c:60:cd:c5:a3:d1:e1:ea:da:
        24:c2:6a:06:d5:dc:1c:71:c9:64:fa:9e:c9:ca:97:e2:06:84:
        de:4c:69:b8:9a:af:66:14:8d:46:9a:00:53:13:c9:ab:10:b8:
        09:c2
openssl x509 -req -in clientreq.pem -extfile /usr/lib/ssl/openssl.cnf 
             -extensions /usr/lib/ssl/openssl.cnf -CA CAcert.pem -CAkey serverkey.pem    
             -CAcreateserial -out clientcert.pem

Подписать запрос на сертификацию (-req) файла -in, используя доверенный CA сертификат -CA и его секретный ключ -CAkey. В конечный сертификат клиента (-out), записываются дополнительные параметры сертификата 3-й версии из файла /usr/lib/ssl/openssl.cnf (конфигурационный файл по умолчанию). Но об этом я расскажу после на конкретном примере. Такое поведение x509 позволяет организовать свой центр сертификации, подписывающий запросы клиентов на сертификацию.

openssl x509 -in CAcert.pem -addtrust sslclient -alias "myorganization CA" 
             -out CAtrust.pem

Преобразование сертификата -in в доверенный сертификат для использования в SSL-клиентах (sslserver — использование в качестве сертификата сервера, emailProtection — использование в качестве сертификата S/MIME).

Я еще раз хотел бы вернуться к проблеме построения CA. Для использования внутри организации можно использовать self-signed сертификат, но для использования CA вне организации приходится использовать сертификаты, выданные или подписанные сторонней организацией. Во втором случае возникает проблема выбора такой сторонней организации (она легко разрешается для дочерних компаний), которая требует юридического анализа (в разных странах существуют свои законы криптографии и поэтому дать какой-либо конкретный совет я не могу). Если вам довелось работать в российской правительственной компании, то считайте, что вам не повезло — использовать openssl для работы с правительственными организациями нельзя. Наши уважаемые гос. деятели добавили геморроя админам, разрешив использовать только алгоритмы ГОСТ (симметрические, асимметрические, хеширования), поэтому использовать вам придется только специальные программы, реализующие эти алгоритмы. Я же приведу здесь пример построение собственного CA с self-signed сертификатом:

1) Генерируем секретный ключ:

openssl genrsa -out CAkey.pem -rand randfile -des3 4096

2) Создаем self-signed сертификат:

openssl req -new -x509 -key CAkey.pem -out CAcert.pem -days 365 -config cfg

Содержимое конфигурационного файла зависит от организации, можно даже воспользоваться утилитой /usr/lib/ssl/misc/CA.pl -newcert, которая создаст ключ и сертификат в одном файле в интерактивном режиме (хотя мне этот вариант не очень понравился, лучше один раз написать нормальный конфиг) — о дополнительных требованиях к конфигурации CA сертификата см. ниже.

3) Приведу пример скрипта, генерирующего клиентские сертификаты:

#!/bin/bash
dd if=/dev/random of=/tmp/.rnd count=64 RAND="/var/log/messages:/boot/vmlinuz:/tmp/.rnd" REQ="openssl req" X509="openssl x509" RSA="openssl rsa" GENRSA="openssl genrsa" O="company" C="RU" ST="region" L="city" PURPOSES="digitalSignature, keyEncipherment" CERTTYPE="client, email, objsign" CA="/etc/openssl/CAcert.pem" CAkey="/etc/openssl/CAkey.pem" OUTDIR="/etc/openssl/clientcert/" CN="client" BITS=2048 DAYS=365
#Создаем секретный ключ во временной папке БЕЗ шифрования TMP="/tmp/ssl-$$" mkdir $TMP
if [ ! -d $OUTDIR ];then mkdir $OUTDIR fi
pushd $TMP > /dev/null $GENRSA -rand $RAND -out tmp.key $BITS
# Создаем конфиг для клиента cat > cfg <<EOT [ req ] default_bits = $BITS distinguished_name = req_DN extensions = v3_req [ req_DN ] countryName = "1. Country Name (2 letter code)" countryName_default = "$C" countryName_min = 2 countryName_max = 2 stateOrProvinceName = "2. State or Province Name (full name) " stateOrProvinceName_default = "$ST" localityName = "3. Locality Name (eg, city) " localityName_default = "$L" 0.organizationName = "4. Organization Name (eg, company) " 0.organizationName_default = "$O" organizationalUnitName = "5. Organizational Unit Name (eg, section) " organizationalUnitName_default = "$OU" commonName = "6. Common Name (eg, CA name) " commonName_max = 64 commonName_default = "$CN" emailAddress = "7. Email Address (eg, name@FQDN)" emailAddress_max = 40 emailAddress_default = "" [ v3_req ] basicConstraints = CA:FALSE keyUsage = $PURPOSES nsCertType = $CERTTYPE EOT # Создаем запрос на сертификацию $REQ -new -key tmp.key -config cfg -rand $RAND -out $CN.pem
# Этот файл лучше удалить побыстрее: мало ли чего... rm -fr /tmp/.rnd
if [ $? -ne 0 ]; then echo "Failed to make a certificate due to error: $?" popd > /dev/null rm -fr $TMP exit $? fi # Подписываем сертификат сертификатом сервера
$X509 -req -in $CN.pem -CA $CA -CAkey $CAkey -CAsetserial -extensions -config cfg -days $DAYS -out $OUTDIR$CN.pem
chmod 0400 $OUTDIR$CN.pem chown root:root $OUTDIR$CN.pem # Шифруем секретный ключ $RSA -in tmp.key -des3 -out $OUTDIR$CN-key.pem
chmod 0400 $OUTDIR$CN-key.pem chown root:root $OUTDIR$CN-key.pem # Выполняем заключительные действия popd > /dev/null
rm -fr $TMP
echo -e "Generation complete, go to $OUTDIR and give to client $CN his certificate and n private key (for windows users you should use openssl pkcs12 utility)"

Дополнительные свойства, описанные в скрипте (v3_req), означают, что клиент может использовать сертификат для подписывания и шифрации, но его сертификат не является CA сертификатом. Для CA-сертификата значение basicConstraits должно быть равно CA:TRUE (об этом забывать нельзя!). Поле nsCertType определяет дополнительные назначения данного ключа (для использования в качестве клиента, подписывания, использования в почтовых сообщениях). Для CA-сертификатов обычно применяют следующие значения nsCertType: sslCA, emailCA. Для ssl-ключей серверов (например, Apache) используется значение nsCertType = server. Полученный таким образом сертификат клиента будет содержать информацию о поставщике сертификата (то есть о вашем сертификате организации). Клиенту необходимо будет передать его сертификат, его секретный ключ (зашифрованный!) и ваш сертификат организации. Для клиентов Micro$oft необходимо еще и перевести сертификаты в формат PKCS#12.

Для этого воспользуемся командой openssl pkcs12:

openssl pkcs12 -export -in client.pem -inkey client-key.pem -out client.p12 
               -name "Client certificate from our organization»

Для обратного преобразования используется синтаксис:

openssl pkcs12 -in client.p12 -out client.pem

В выходной файл записываются сертификат клиента, ca сертификат, секретный ключ клиента (его можно зашифровать опцией -des3, -idea и.т.д.). Такое поведение позволяет использовать для вывода только формат pem (маркеры здесь обязательны!). Для экспорта сертификата организации можно воспользоваться командой pkcs12 (конечно же, без параметра inkey ;), можно также обработать сертификат организации base64 и сохранить в файле .cer (openssl x509 -in CA.pem -outform DER -out CA.cer).

В openssl существует компонент управления s/mime-сообщениями, называющийся openssl smime. Данная утилита позволяет зашифровывать, расшифровывать, управлять ЭЦП и MIME-заголовками писем. Приведу опять же несколько примеров ее использования:

openssl smime -sign -in mail.txt -text -from CEBKA@smtp.ru -to 
              user@mail.ru -subject "Signed message" -signer mycert.pem -inkey 
              private_key.pem | sendmail user@mail.ru

Подписывает сообщение -in (в текстовом виде) и подписывает (-sign) его с помощью сертификата (-signer) и секретного ключа (-inkey). Вывод идет непосредственно к sendmail, для этого определены MIME-заголовки from, to и subject.

openssl smime -verify -in mail.msg -signer user.pem -out signedtext.txt

Проверяет подпись в файле -in, записывает сообщение в файл -out, а полученный сертификат — в файл -signer (для проверки s/mime-сообщения не требуется ничего, кроме него самого, т.к. ЭЦП s/mime содержит публичный ключ!).

openssl smime -encrypt -in mail.txt -from CEBKA@smtp.ru -to user@mail.ru 
              -subject "Encrypted message" -des3 user.pem | sendmail     
              user@mail.ru

Шифрация файла -in с помощью сертификата получателя «user.pem», используя алгоритм «des3». Вывод программы посылается непосредственно в sendmail.

openssl smime -decrypt -in mail.msg -recip mycert.pem -inkey private_key.pem 
              -out mail.txt

Расшифровка файла -in с помощью секретного ключа -inkey и сертификата -recip (ваш собственный сертификат).

Есть альтернатива не указывать smime-заголовки from, to и subject. Можно просто указать необходимый файл -out и добавить заголовки с помощью программы sendmail вручную. Кроме этого, есть еще одна деталь использования smime: некоторые почтовые клиенты используют в качестве подписи вложение в формате PKCS#7 (чаще всего закодированное base64). В таком случае необходимо применять smime следующим образом:

openssl smime -verify -inform [PEM | DER] -in signature.pem[der] -content 
              mail.txt

PEM используется для стандартного формата PKCS#7, а DER заставляет произвести дополнительную обработку base64. Учтите, что в данном случае файл -in представляет собой только подпись (аттачмент), а -content — непосредственно текст письма. Можно также заставить smime подписывать сообщения подобным образом, если указать опцию -pk7out (PEM формат). Для преобразования PKCS#7 структуры из формата PEM в формат DER можно воспользоваться утилитой openssl base64 (обратное преобразование достигается за счет использования опции -d).

Итак, думаю, что для большинства операций с использованием SSL этого будет достаточно.

OpenSSL — проект с открытым исходным кодом, состоящий из криптографической библиотеки и набора инструментов SSL/TLS. Цитата с веб-сайта проекта:

Проект OpenSSL Project — это совместный труд по разработке надёжного полнофункционального Open Source-инструментария коммерческого класса, реализующего протоколы Secure Sockets Layer (SSL) и Transport Layer Security (TLS), а также полнофункциональную криптографическую библиотеку общего назначения. Проект управляется сообществом добровольцев со всего мира, использующим Интернет для взаимодействия, планирования и разработки инструментария OpenSSL, а также связанной с ним документации.

OpenSSL является стандартом де-факто в этой области и имеет продолжительную историю. Первоначально проект стартовал в 1995 году под названием SSLeay1, тогда его разработкой занимались Eric A. Young и Tim J. Hudson. Рождение проекта OpenSSL произошло в конце 1998 года, когда Эрик и Тим прекратили свою работу над SSLeay, чтобы работать над коммерческим инструментарием SSL/TLS под названием BSAFE SSL-C в RSA Australia.

Сегодня OpenSSL получил повсеместное распространение как на серверах, так и во многих клиентских программах. Его инструменты командной строки чаще всего выбираются для управления сертификатами, а также для их проверки. Что интересно, в браузерах исторически использовались другие библиотеки, но и это сейчас меняется, поскольку Google переводит Chrome на свой собственный форк OpenSSL, называемый BoringSSL2.

У OpenSSL две лицензии: OpenSSL и SSLeay. Обе схожи с лицензией BSD с оговорками о рекламе. Эти лицензии долгое время были источниками раздора, поскольку ни одна из них не считается совместимой с семейством лицензий GPL. Именно по этой причине программы, лицензированные по лицензии GPL, часто отдают предпочтение GnuTLS.

Начало работы

Если вы используете одну из Unix-платформ, начать работать с OpenSSL легко; практически гарантированно, что в вашей системе он уже есть. Единственная проблема, с которой вы можете столкнуться — то, что у вас может не оказаться последней версии. В данном разделе подразумевается, что вы используете Unix-платформу, потому что это естественная среда для OpenSSL.

Пользователи Windows, как правило, загружают двоичные файлы, что может немного усложнить ситуацию. В простейшем случае, если вам нужны только утилиты командной строки, на основном сайте OpenSSL для Windows-бинарников указана ссылка на сборку от Shining Light Productions3. Во всех остальных ситуациях вам необходимо убедиться, что вы не пытаетесь совместно использовать бинарники, скомпилированные на основе разных версий OpenSSL, иначе могут возникать сбои, которые трудно будет выявить и устранить. Наилучшим подходом будет использование единого пакета программ, который включает в себя всё, что вам нужно. Например, если вы хотите запускать Apache на Windows, вы можете получить требуемые бинарники в сборке Apache Lounge4.

Определение версии и конфигурации OpenSSL

Перед тем, как что-либо сделать, вам необходимо узнать, какую версию OpenSSL вы используете. Например, вот так я получаю информацию о версии с помощью команды openssl version на Ubuntu 12.04 LTS — системе, которую я буду использовать в примерах этой главы:

$ openssl version
OpenSSL 1.0.1 14 Mar 2012

На момент написания этого материала происходил переход от OpenSSL 0.9.x к OpenSSL 1.0.x. Версия 1.0.1 особенно важна, поскольку это первая версия, поддерживающая TLS 1.1 и 1.2. Поддержка более новых протоколов является частью глобального тренда, поэтому вполне вероятно, что в ближайший период мы нередко будем сталкиваться с проблемами совместимости.

Примечание: Часто сборщики различных операционных систем модифицируют исходный код OpenSSL, обычно для устранения выявленных проблем. Однако название проекта и номер версии, как правило, оставляют неизменными, и нет никаких признаков того, что данный код на самом деле является ответвлением исходного проекта и будет вести себя по-другому. Например, версия OpenSSL, используемая в Ubuntu 12.04 LTS5, основана на OpenSSL 1.0.1c. На момент написания этого материала полное имя установочного пакета было openssl 1.0.1-4ubuntu5.16, и этот пакет включал исправления для многих проблем, которые были выявлены с течением времени.

Для получения полной информации о версии используйте опцию -a:

$ openssl version -a
OpenSSL 1.0.1 14 Mar 2012
built on: Fri Jun 20 18:54:15 UTC 2014
platform: debian-amd64
options:  bn(64,64) rc4(8x,int) des(idx,cisc,16,int) blowfish(idx)
compiler: cc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN ↩
-DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector --param=ssp-buffer-size↩
=4 -Wformat -Wformat-security -Werror=format-security -D_FORTIFY_SOURCE=2 ↩
-Wl,-Bsymbolic-functions -Wl,-z,relro -Wa,--noexecstack -Wall -DOPENSSL_NO_TLS1_2↩
_CLIENT -DOPENSSL_MAX_TLS1_2_CIPHER_LENGTH=50 -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 ↩
-DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256↩
_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH↩
_ASM
OPENSSLDIR: "/usr/lib/ssl"

Последняя строка в данном выводе (/usr/lib/ssl) особенно интересна, поскольку она говорит вам о том, где OpenSSL будет искать собственную конфигурацию и сертификаты. В моей системе это местоположение, по существу, является псевдонимом для директории /etc/ssl, где Ubuntu хранит файлы, связанные с TLS:

lrwxrwxrwx  1 root root   14 Apr 19 09:28 certs -> /etc/ssl/certs
drwxr-xr-x  2 root root 4096 May 28 06:04 misc
lrwxrwxrwx  1 root root   20 May 22 17:07 openssl.cnf -> /etc/ssl/openssl.cnf
lrwxrwxrwx  1 root root   16 Apr 19 09:28 private -> /etc/ssl/private

Директория misc/ содержит несколько дополнительных скриптов, наиболее интересными из которых являются скрипты, позволяющие реализовать приватный центр сертификации или удостоверяющий центр (УЦ).

Сборка OpenSSL

В большинстве случаев вы будете использовать версию OpenSSL, поставляемую с операционной системой, но иногда есть веские причины для обновления. Например, ваша система могла застрять на OpenSSL 0.9.x, не поддерживающей новые версии протокола TLS, но даже если в вашей системе правильная версия OpenSSL, в ней может не быть необходимого вам функционала. Например, на Ubuntu 12.04 LTS нет поддержки SSL 2 в команде s_client. Хотя отсутствие по умолчанию поддержки этой версии SSL является правильным решением, вам может понадобиться данный функционал, если вы регулярно тестируете другие серверы на поддержку SSL 2.

Вы можете начать с загрузки самой последней версии OpenSSL (в моем случае, 1.0.1p):

$ wget http://www.openssl.org/source/openssl-1.0.1p.tar.gz

Следующий шаг — конфигурирование OpenSSL перед компиляцией. В большинстве случаев системная версия оставляется в покое и OpenSSL устанавливается в другое место. Например:

$ ./config 
--prefix=/opt/openssl 
--openssldir=/opt/openssl 
enable-ec_nistp_64_gcc_128

Параметр enable-ec_nistp_64_gcc_128 активирует оптимизированные версии некоторых часто используемых эллиптических кривых. Данная оптимизация зависит от функции компилятора, которая не может быть обнаружена автоматически, поэтому по умолчанию этот параметр отключен.

Примечание: Если вы компилируете версию OpenSSL из ветки 1.1.x или выше, то, по крайней мере в некоторых системах, вам нужно будет использовать параметр no-shared для создания статически скомпилированных инструментов командной строки. Вы поймёте, что нужно использовать этот параметр, если (после компиляции) при попытке вызвать бинарник OpenSSL он будет жаловаться на то, что не может найти некоторые требуемые ему разделяемые библиотеки.

Затем нужно будет выполнить следующие команды:

$ make depend
$ make
$ sudo make install

В итоге в директории /opt/openssl у вас будет такое содержимое:

drwxr-xr-x 2 root root  4096 Jun  3 08:49 bin
drwxr-xr-x 2 root root  4096 Jun  3 08:49 certs
drwxr-xr-x 3 root root  4096 Jun  3 08:49 include
drwxr-xr-x 4 root root  4096 Jun  3 08:49 lib
drwxr-xr-x 6 root root  4096 Jun  3 08:48 man
drwxr-xr-x 2 root root  4096 Jun  3 08:49 misc
-rw-r--r-- 1 root root 10835 Jun  3 08:49 openssl.cnf
drwxr-xr-x 2 root root  4096 Jun  3 08:49 private

Директория private/ пуста, но это нормально: у вас ещё нет каких-либо закрытых ключей. С другой стороны, вы, вероятно, удивитесь, узнав, что директория certs/ тоже пуста. В OpenSSL не включено никаких корневых сертификатов; подразумевается, что поддержание доверенного хранилища выходит за рамки проекта. К счастью, в состав вашей операционной системы, скорее всего, уже входит доверенное хранилище, которое можно использовать. Кроме того, как мы продемонстрируем в одном из следующих разделов, вы можете без особого труда построить своё собственное.

Примечание: При компиляции программного обеспечения важно хорошо разбираться с настройками по умолчанию вашего компилятора. Пакеты, распространяемые с системой, обычно компилируются с использованием всех доступных параметров повышения безопасности, но при самостоятельной компиляции какого-то программного обеспечения нет гарантии, что будут применяться те же параметры6.

Просмотр доступных команд

OpenSSL — это криптографический инструментарий, состоящий из множества различных утилит. В моей версии я насчитал 46. Тот самый случай, когда уместно употребить фразу Швейцарский армейский нож криптографии, так оно и есть. Даже если вы будете использовать всего несколько утилит, вам следует ознакомиться со всеми доступными, поскольку неизвестно, что может понадобиться в будущем.

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

$ openssl help
openssl:Error: 'help' is an invalid command.

Standard commands
asn1parse         ca                ciphers           cms
crl               crl2pkcs7         dgst              dh
dhparam           dsa               dsaparam          ec
ecparam           enc               engine            errstr
gendh             gendsa            genpkey           genrsa
nseq              ocsp              passwd            pkcs12
pkcs7             pkcs8             pkey              pkeyparam
pkeyutl           prime             rand              req
rsa               rsautl            s_client          s_server
s_time            sess_id           smime             speed
spkac             srp               ts                verify
version           x509

Первая часть справки выводит список всех доступных утилит. Чтобы получить больше информации о конкретной утилите, используйте man с именем этой утилиты. Например, man ciphers выдаст подробную информацию о том, как настроены наборы алгоритмов шифрования (наборы шифров).

Вывод справки этим не заканчивается, но остальное несколько менее интересно. Во второй части вы увидите список команд для работы с дайджестами сообщений (алгоритмами хэширования):

Message Digest commands (see the `dgst’ command for more details)
md4 md5 rmd160 sha
sha1

И, наконец, в третьей части вы увидите список всех команд для работы с шифрами:

Cipher commands (see the `enc' command for more details)
aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb
aes-256-cbc       aes-256-ecb       base64            bf
bf-cbc            bf-cfb            bf-ecb            bf-ofb
camellia-128-cbc  camellia-128-ecb  camellia-192-cbc  camellia-192-ecb
camellia-256-cbc  camellia-256-ecb  cast              cast-cbc
cast5-cbc         cast5-cfb         cast5-ecb         cast5-ofb
des               des-cbc           des-cfb           des-ecb
des-ede           des-ede-cbc       des-ede-cfb       des-ede-ofb
des-ede3          des-ede3-cbc      des-ede3-cfb      des-ede3-ofb
des-ofb           des3              desx              rc2
rc2-40-cbc        rc2-64-cbc        rc2-cbc           rc2-cfb
rc2-ecb           rc2-ofb           rc4               rc4-40
seed              seed-cbc          seed-cfb          seed-ecb
seed-ofb          zlib

Построение доверенного хранилища

Вместе с OpenSSL не поставляется каких-либо доверенных корневых сертификатов (ещё говорят доверенное хранилище), так что если вы выполняете установку с нуля, то придётся поискать их где-то на стороне. Один из возможных вариантов — использовать доверенное хранилище, встроенное в вашу операционную систему. Обычно этот вариант хорош, но доверенные хранилища, имеющиеся в операционной системе по умолчанию, могут не всегда быть актуальны. Лучший (но более трудоёмкий) вариант — обратиться к Mozilla, которые прилагают много усилий для поддержания надёжного доверенного хранилища. Далее будет приведён реальный пример, как я получал доверенное хранилище для своего инструмента оценки в SSL Labs.

Поскольку проекты Mozilla с открытым исходным кодом, их доверенное хранилище можно найти в репозитории исходного кода:

https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt

К сожалению, их коллекция сертификатов находится в проприетарном формате, который в исходном состоянии нам бесполезен. Если у вас нет предрассудков в смысле получения этой коллекции от третьих лиц, проект Curl предоставляет регулярно обновляемую сконвертированную в формат Privacy-Enhanced Mail (PEM) версию, которую вы можете использовать сразу:

http://curl.haxx.se/docs/caextract.html

Но даже если вы скачаете коллекцию напрямую с сайта Mozilla, вам не придётся самостоятельно писать скрипт конвертации. Такие скрипты доступны на языках Perl и Go, их использование будет описано в следующих разделах.

Примечание: Если вы всё же решите написать собственный скрипт преобразования, имейте ввиду, что файл корневых сертификатов от Mozilla фактически содержит два типа сертификатов: доверенные (являющиеся частью хранилища), а также явно недоверенные. В Mozilla используют такой механизм для запрета скомпрометированных сертификатов промежуточных УЦ (например, старых сертификатов DigiNotar). Оба описанных далее инструмента работы с файлом Mozilla достаточно разборчивы и способны исключить недоверенные сертификаты в процессе конвертации.

Конвертация с использованием Perl

Проект Curl обнародовал Perl-срипт, написанный Guenter Knauf, который может быть использован для конвертации доверенного хранилища Mozilla:

https://raw.github.com/bagder/curl/master/lib/mk-ca-bundle.pl

После скачивания и запуска скрипта он извлечёт данные сертификатов из хранилища Mozilla и преобразует их в формат PEM:

$ ./mk-ca-bundle.pl
Downloading 'certdata.txt' ...
Processing  'certdata.txt' ...
Done (156 CA certs processed, 19 untrusted skipped).

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

Конвертация с использованием Go

Если вы предпочитаете язык программирования Go, обратите внимание на инструмент конвертации от Adam Langley, который можно получить на GitHub:

https://github.com/agl/extract-nss-root-certs

Для выполнения конвертации сначала скачайте сам инструмент:

$ wget https://raw.github.com/agl/extract-nss-root-certs/master/convert_mozilla_certdata.go

А потом данные сертификатов от Mozilla:

$ wget https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt --output-document certdata.txt

Наконец, переконвертируйте файл следующей командой:

$ go run convert_mozilla_certdata.go > ca-certificates
2012/06/04 09:52:29 Failed to parse certificate starting on line 23068: negative serial number 

В моём случае имел место некорректный сертификат, который не смогла обработать библиотека X.509 языка Go, но обычно конвертация проходит без эксцессов. Версии Go, начиная с версии 1.6 и выше, не должны выдавать это предупреждение, поскольку они могут обрабатывать сертификаты с отрицательными серийными номерами.

Управление ключами и сертификатами

Большинство пользователей обращаются к OpenSSL, потому что хотят настроить и запустить веб-сервер с поддержкой SSL. Этот процесс состоит из трёх этапов: (1) генерация стойкого закрытого ключа, (2) создание запроса на подписание сертификата (Certificate Signing Request, CSR) и направление его в УЦ, и (3) инсталляция предоставленного УЦ сертификата в ваш веб-сервер. Об этих (и некоторых других) этапах пойдёт речь в данном разделе.

Генерация ключа

Первым шагом в подготовке к использованию асимметричного шифрования является создание закрытого ключа. Прежде чем начать, вы должны принять несколько решений:

Ключевой алгоритм

OpenSSL поддерживает ключи RSA, DSA и ECDSA, но не все типы безоговорочно подходят для любого сценария использования. Например, в качестве ключа веб-сервера повсеместно используется RSA, поскольку ключи DSA по существу ограничены 1024 битами (Internet Explorer не поддерживает ничего более стойкого), а ключи ECDSA ещё не получили широкой поддержки УЦ. Для SSH везде используются DSA и RSA, поскольку ECDSA может не поддерживаться всеми клиентами.

Размер ключа

Размер ключа по умолчанию может быть небезопасным, поэтому его всегда следует настраивать явно. Например, размер по умолчанию для ключей RSA всего 512 бит, что попросту небезопасно. Если в наши дни вы будете использовать на своём сервере ключ длиной 512 бит, злоумышленник, получив ваш сертификат, может простым перебором (методом «грубой силы») подобрать ваш закрытый ключ, после чего он или она сможет выдавать себя за ваш веб-сайт. В наши дни безопасными считаются ключи RSA в 2048 бит, их и нужно использовать. Также необходимо использовать ключи DSA длиной 2048 бит и не менее 256 бит для ECDSA.

Кодовая фраза

Использовать кодовую фразу (passphrase) с ключом необязательно, но настоятельно рекомендуется. Защищённые ключи можно безопасно хранить, транспортировать и создавать резервные копии. С другой стороны, такие ключи неудобны, поскольку без ввода кодовой фразы их использовать нельзя. Например, запрос на ввод кодовой фразы может возникать каждый раз, когда вы захотите перезапустить ваш веб-сервер. В большинстве случаев это либо слишком неудобно, либо создаёт неприемлемые условия для доступности сервисов. Кроме того, использование защищённых ключей в рабочей среде на самом деле не сильно повышает безопасность (если вообще повышает). Это связано с тем, что после первоначальной активации закрытые ключи хранятся в незащищённом виде в памяти программы; злоумышленник, проникнувший на сервер, может получить ключи оттуда, приложив при этом лишь немного больше усилий. Так что кодовые фразы следует рассматривать только в качестве механизма защиты закрытого ключа, пока он не установлен в рабочей среде. Другими словами, нет ничего страшного в том, чтобы в рабочей среде хранить кодовые фразы рядом с ключами. Если же в рабочей среде вам требуется повышенная безопасность, стоит рассмотреть вариант с инвестированием в аппаратные решения7.

Для генерации ключа RSA используйте команду genrsa:

$ openssl genrsa -aes128 -out fd.key 2048
Generating RSA private key, 2048 bit long modulus
....+++
...................................................................................+++
e is 65537 (0x10001)
Enter pass phrase for fd.key: ****************
Verifying - Enter pass phrase for fd.key: ****************

Здесь я указал, что ключ будет защищён с помощью AES-128. Также вы можете использовать AES-192 или AES-256 (параметры -aes192 и -aes256, соответственно), но лучше воздержаться от применения других алгоритмов (DES, 3DES и SEED).

Предупреждение: Значение e, которое вы видите в выводе, относится к открытой экспоненте (public exponent), которая по умолчанию установлена в 65537. Это так называемая короткая открытая экспонента, и она значительно повышает производительность верификации RSA. При использовании параметра -3 можно выбрать в качестве открытой экспоненты число 3 и сделать верификацию ещё быстрее. Однако в истории было несколько неприятных происшествий, связанных с использованием числа 3 в качестве открытой экспоненты, поэтому, как правило, всем рекомендуется придерживаться числа 65537, обеспечивая тем самым запас прочности с исторически доказанной эффективностью.

Закрытые ключи хранятся в так называемом PEM-формате, представляющем собой просто текст:

$ cat fd.key
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,01EC21976A463CE36E9DB59FF6AF689A

vERmFJzsLeAEDqWdXX4rNwogJp+y95uTnw+bOjWRw1+O1qgGqxQXPtH3LWDUz1Ym
mkpxmIwlSidVSUuUrrUzIL+V21EJ1W9iQ71SJoPOyzX7dYX5GCAwQm9Tsb40FhV/
[21 lines removed...]
4phGTprEnEwrffRnYrt7khQwrJhNsw6TTtthMhx/UCJdpQdaLW/TuylaJMWL1JRW
i321s5me5ej6Pr4fGccNOe7lZK+563d7v5znAx+Wo1C+F7YgF+g8LOQ8emC+6AVV
-----END RSA PRIVATE KEY-----

Закрытый ключ — это не просто набор случайных данных, как может показаться на первый взгляд. Структуру ключа можно увидеть, используя следующую команду rsa:

$ openssl rsa -text -in fd.key
Enter pass phrase for fd.key: ****************
Private-Key: (2048 bit)
modulus:
    00:9e:57:1c:c1:0f:45:47:22:58:1c:cf:2c:14:db:
    [...]
publicExponent: 65537 (0x10001)
privateExponent:
    1a:12:ee:41:3c:6a:84:14:3b:be:42:bf:57:8f:dc:
    [...]
prime1:
    00:c9:7e:82:e4:74:69:20:ab:80:15:99:7d:5e:49:
    [...]
prime2:
    00:c9:2c:30:95:3e:cc:a4:07:88:33:32:a5:b1:d7:
    [...]
exponent1:
    68:f4:5e:07:d3:df:42:a6:32:84:8d:bb:f0:d6:36:
    [...]
exponent2:
    5e:b8:00:b3:f4:9a:93:cc:bc:13:27:10:9e:f8:7e:
    [...]
coefficient:
    34:28:cf:72:e5:3f:52:b2:dd:44:56:84:ac:19:00:
    [...]
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
[...]
-----END RSA PRIVATE KEY-----

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

$ openssl rsa -in fd.key -pubout -out fd-public.key
Enter pass phrase for fd.key: ****************

Заглянув во вновь созданный файл, можно увидеть метки, ясно указывающие на то, что содержимое действительно является открытой информацией:

$ cat fd-public.key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnlccwQ9FRyJYHM8sFNsY
PUHJHJzhJdwcS7kBptutf/L6OvoEAzCVHi/m0qAA4QM5BziZgnvv+FNnE3sgE5pz
iovEHJ3C959mNQmpvnedXwfcOIlbrNqdISJiP0js6mDCzYjSO1NCQoy3UpYwvwj7
0ryR1F+abARehlts/Xs/PtX3VamrljiJN6JNgFICy3ZvEhLZEKxR7oob7TnyZDrj
IHxBbqPNzeiqLCFLFPGgJPa0cH8DdovBTesvu7wr/ecsf8CYyUCdEwGkZh9DKtdU
HFa9H8tWW2mX6uwYeHCnf2HTw0E8vjtOb8oYQxlQxtL7dpFyMgrpPOoOVkZZW/P0
NQIDAQAB
-----END PUBLIC KEY-----

Лишний раз убедиться в том, что на выходе вы получили именно то, что хотели — это хорошая практика. Например, если вы забудете указать в командной строке параметр -pubout, выходной файл будет содержать ваш закрытый ключ вместо открытого.

Генерация ключа DSA происходит в два этапа: на первом создаются параметры DSA, а на втором — ключ. Можно выполнять их последовательно один за другим, но мне больше нравится использовать следующие две команды как одну:

$ openssl dsaparam -genkey 2048 | openssl dsa -out dsa.key -aes128
Generating DSA parameters, 2048 bit long prime
This could take some time
[...]
read DSA key
writing DSA key
Enter PEM pass phrase: ****************
Verifying - Enter PEM pass phrase: ****************

Этот подход позволяет мне генерировать защищённый кодовой фразой ключ, не оставляя при этом никаких временных файлов (с параметрами DSA) и/или временных ключей на диске.

Для ключей ECDSA процесс аналогичен, за исключением того, что отсутствует возможность создать ключи произвольных размеров. Вместо этого для каждого ключа вы выбираете именованную кривую (named curve), которая контролирует размер ключа, а также другие параметры EC. В следующем примере создаётся 256-битный ключ ECDSA с использованием именованной кривой secp256r1:

$ openssl ecparam -genkey -name secp256r1 | openssl ec -out ec.key -aes128
using curve name prime256v1 instead of secp256r1
read EC key
writing EC key
Enter PEM pass phrase: ****************
Verifying - Enter PEM pass phrase: ****************

OpenSSL поддерживает много именованных кривых (полный список можно получить с помощью параметра -list_curves), но для ключей веб-сервера выбор ограничен лишь двумя кривыми, которые поддерживаются всеми основными браузерами: secp256r1 (в OpenSSL используется имя prime256v1) и secp384r1.

Примечание: Если вы используете OpenSSL 1.0.2, вы можете сэкономить время, всегда генерируя ключи с помощью команды genpkey, которая была усовершенствована для поддержки различных типов ключей и параметров конфигурации. В настоящее время она представляет собой унифицированный интерфейс для генерации ключей.

Создание запроса на подписание сертификата

Получив закрытый ключ, вы можете приступить к созданию запроса на подписание сертификата (Certificate Signing Request, CSR). Это формализованный запрос в УЦ о подписании сертификата, в котором содержится открытый ключ объекта, запрашивающего сертификат, а также некоторая информация об этом объекте. Все эти данные будут частью будущего сертификата. CSR всегда подписывается закрытым ключом, соответствующим тому открытому ключу, который содержится в запросе.

Обычно создание CSR представляет собой интерактивный процесс, в ходе которого вам потребуется предоставить элементы уникального имени объекта сертификата. Внимательно читайте инструкции, выдаваемые инструментом openssl; если вы хотите оставить поле пустым, вы должны ввести в строку запроса символ точки (.), а не просто нажать клавишу «Ввод» (в этом случае OpenSSL заполнит соответствующее поле CSR значением по умолчанию). Согласие со значениями по умолчанию не имеет никакого смысла, когда при генерации CSR используется конфигурация OpenSSL по умолчанию (весьма распространённая практика). И наоборот, вполне резонно соглашаться со значениями по умолчанию, когда вы их сами задали, либо поменяв конфигурацию OpenSSL, либо предоставив свои собственные файлы конфигурации.

$ openssl req -new -key fd.key -out fd.csr
Enter pass phrase for fd.key: ****************
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:GB
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:London
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Feisty Duck Ltd
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:www.feistyduck.com
Email Address []:webmaster@feistyduck.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Примечание: В соответствии с разделом 5.4.1 RFC 29858, проблемный пароль (challenge password) является необязательным полем, предназначенным для использования во время отзыва сертификата как способ идентификации исходного объекта, запросившего данный сертификат. Если этот пароль введен, он будет дословно включён в CSR и передан в УЦ. Редко можно найти УЦ, обрабатывающий данное поле; во всех инструкциях, которые я видел, рекомендуется оставить его незаполненным. Задание проблемного пароля никоим образом не повышает безопасность CSR. Кроме того, это поле не следует путать с кодовой фразой, которая является отдельной характеристикой.

После генерации CSR он используется для подписания своего собственного сертификата и/или отправки в публичный УЦ с просьбой подписать сертификат. Оба подхода будут описаны в последующих разделах. Но прежде чем сделать это, стоит ещё раз проверить правильность CSR. Это делается так:

$ openssl req -text -in fd.csr -noout
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=GB, L=London, O=Feisty Duck Ltd, CN=www.feistyduck.com↩
/emailAddress=webmaster@feistyduck.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b7:fc:ca:1c:a6:c8:56:bb:a3:26:d1:df:e4:e3:
                    [ещё 16 строк...]
                    d1:57
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: sha1WithRSAEncryption
         a7:43:56:b2:cf:ed:c7:24:3e:36:0f:6b:88:e9:49:03:a6:91:
         [ещё 13 строк...]
         47:8b:e3:28

Создание CSR из существующего сертификата

Если вы продлеваете сертификат и не хотите вносить какие-либо изменения в представленную в нём информацию, можно упростить себе жизнь и печатать немного поменьше. С помощью следующей команды вы сможете создать новенький CSR из существующего сертификата:

$ openssl x509 -x509toreq -in fd.crt -out fd.csr -signkey fd.key

Примечание: За исключением случаев применения некоторой формы привязывания открытого ключа (public key pinning), при которых вы захотите продолжать использовать существующий ключ, лучшей практикой считается генерация нового ключа каждый раз при запросе нового сертификата. Генерация ключей — быстрая и недорогая операция, к тому же значительно снижающая ваши риски.

Автоматизированная генерация CSR

Генерация CSR не обязательно должна быть интерактивной. Используя отличный от поставляемого по умолчанию файл конфигурации OpenSSL, вы можете решить сразу две задачи: автоматизировать процесс (как объясняется в этом разделе), а также сделать некоторые вещи, которые невозможны в интерактивном режиме (мы обсудим это в последующих разделах).

Например, предположим, что вы хотите автоматизировать генерацию CSR для www.feistyduck.com. Для начала нужно создать файл fd.cnf следующего содержания:

[req]
prompt = no
distinguished_name = dn
req_extensions = ext
input_password = PASSPHRASE

[dn]
CN = www.feistyduck.com
emailAddress = webmaster@feistyduck.com
O = Feisty Duck Ltd
L = London
C = GB

[ext]
subjectAltName = DNS:www.feistyduck.com,DNS:feistyduck.com

Ну а теперь можно создать CSR прямо из командной строки:

$ openssl req -new -config fd.cnf -key fd.key -out fd.csr

Подписание своего собственного сертификата

Если вы устанавливаете TLS-сервер для внутреннего использования, вам, вероятно, нет нужды обращаться в УЦ за публично доверенным сертификатом. Гораздо проще просто использовать самоподписанный сертификат. Если вы пользуетесь браузером Firefox, при первом посещении веб-сайта можно создать исключение для вашего сертификата, после чего этот сайт будет столь же безопасен, как если бы он был защищён публично доверенным сертификатом.

Если у вас уже есть CSR, создайте сертификат следующей командой:

$ openssl x509 -req -days 365 -in fd.csr -signkey fd.key -out fd.crt
Signature ok
subject=/CN=www.feistyduck.com/emailAddress=webmaster@feistyduck.com/O=Feisty Duck Ltd↩
/L=London/C=GB
Getting Private key
Enter pass phrase for fd.key: ****************

На самом деле вам не нужно отдельно создавать CSR. С помощью следующей команды можно создать самоподписанный сертификат, имея в наличии только ключ:

$ openssl req -new -x509 -days 365 -key fd.key -out fd.crt

Чтобы не отвечать ни на какие вопросы, используйте параметр -subj для предоставления информации о субъекте сертификата в командной строке:

$ openssl req -new -x509 -days 365 -key fd.key -out fd.crt 
 -subj "/C=GB/L=London/O=Feisty Duck Ltd/CN=www.feistyduck.com"

Создание сертификата, действительного для нескольких имен хостов

По умолчанию сертификаты, созданные OpenSSL, имеют только одно поле для общепринятого имени (common name) и действительны только для одного имени хоста. По этой причине, даже если у вас есть связанные веб-сайты, вы будете вынуждены использовать отдельный сертификат для каждого из них. В данной ситуации более оправданным представляется использование одного мультидоменного сертификата. Кроме того, даже если у вас один веб-сайт, необходимо убедиться, что сертификат действителен для всех возможных путей, по которым конечные пользователи могут пытаться получить к нему доступ. На практике это означает использование как минимум двух имен, одно из которых будет с префиксом www, а второе — без него (например, www.feistyduck.com и feistyduck.com).

Существует два механизма поддержки нескольких имен хостов в сертификате. Первый — перечислить все желательные имена, используя расширение X.509, которое называется Альтернативное имя субъекта (Subject Alternative Name, SAN). Второй — использовать шаблоны подстановки (wildcard). Также можно использовать комбинацию этих двух подходов (если это более удобно). На практике, для большинства сайтов можно указать просто доменное имя и шаблон подстановки для охвата всех возможных поддоменов (например, feistyduck.com и *.feistyduck.com).

Предупреждение: Когда в сертификате содержатся альтернативные имена, все общепринятые имена игнорируются. Более новые сертификаты, выпускаемые УЦ, могут даже не содержать общепринятых имён. Поэтому нужно включать все желаемые имена хостов в список альтернативных имён.

Сначала поместите информацию расширения в отдельный текстовый файл. У меня он будет называться fd.ext. В этом файле укажите имя расширения (subjectAltName) и список желаемых имён хостов, как в данном примере:

subjectAltName = DNS:*.feistyduck.com, DNS:feistyduck.com

Затем, используя команду x509, оформите сертификат, указав файл с расширением с помощью параметра -extfile:

$ openssl x509 -req -days 365 
-in fd.csr -signkey fd.key -out fd.crt 
-extfile fd.ext

В остальном процесс ничем не отличается от рассмотренного ранее. Но когда вы в дальнейшем исследуете сгенерированный сертификат, вы обнаружите, что он содержит расширение SAN:

 X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:*.feistyduck.com, DNS:feistyduck.com

Исследование сертификата

На первый взгляд сертификаты могут выглядеть как куча случайных данных, но они содержат много информации; вам нужно только знать, как до неё добраться. Команда x509 делает именно это, поэтому воспользуемся ею, чтобы рассмотреть самоподписанные сертификаты, которые вы сгенерировали.

В следующем примере я использовал параметр -text для печати содержимого сертификата, а также параметр -noout, чтобы не выводить сам закодированный сертификат (что выполняется по умолчанию) и не отвлекать нас от главного:

$ openssl x509 -text -in fd.crt -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 13073330765974645413 (0xb56dcd10f11aaaa5)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: CN=www.feistyduck.com/emailAddress=webmaster@feistyduck.com, O=Feisty ↩
Duck Ltd, L=London, C=GB
        Validity
            Not Before: Jun  4 17:57:34 2012 GMT
            Not After : Jun  4 17:57:34 2013 GMT
        Subject: CN=www.feistyduck.com/emailAddress=webmaster@feistyduck.com, O=Feisty ↩
Duck Ltd, L=London, C=GB
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b7:fc:ca:1c:a6:c8:56:bb:a3:26:d1:df:e4:e3:
                    [ещё 16 строк...]
                    d1:57
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha1WithRSAEncryption
         49:70:70:41:6a:03:0f:88:1a:14:69:24:03:6a:49:10:83:20:
         [ещё 13 строк...]
         74:a1:11:86

Самоподписанные сертификаты обычно содержат только самые базовые данные сертификата, как можно увидеть на примере выше. Для сравнения, сертификаты, выданные публичными удостоверяющими центрами, гораздо интереснее, поскольку они содержат ряд дополнительных полей (добавляемых через механизм расширений X.509). Давайте их бегло рассмотрим.

Расширение Basic Constraints используется для маркировки того, что рассматриваемый сертификат является сертификатом удостоверяющего центра, у которого есть возможность подписи других сертификатов. У сертификатов, которые не являются сертификатами УЦ, это расширение будет либо опущено, либо иметь значение CA, установленное в FALSE. Это расширение является критичным, что означает, что все программы, использующие в работе сертификаты, должны понимать его значение.

X509v3 Basic Constraints: critical
    CA:FALSE

Расширения Key Usage (KU) и Extended Key Usage (EKU) ограничивают то, для чего могут быть использованы сертификаты. Если эти расширения присутствуют, то для сертификата разрешены только перечисленные варианты использования. Если эти расширения отсутствуют, значит ограничений на использование не накладывается. В примере ниже приведены типичные варианты использования для сертификата веб-сервера, который, например, нельзя использовать для подписания кода:

X509v3 Key Usage: critical
    Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
    TLS Web Server Authentication, TLS Web Client Authentication

В расширении CRL Distribution Points перечислены адреса, по которым можно найти списки отзыва сертификатов (Certificate Revocation List, CRL) удостоверяющего центра. Эта информация важна в тех случаях, когда сертификаты необходимо отозвать. CRL представляют собой подписанные УЦ списки отозванных сертификатов, регулярно публикуемые через определённые промежутки времени (например, раз в семь дней).

X509v3 CRL Distribution Points:
    Full Name:
      URI:http://crl.starfieldtech.com/sfs3-20.crl

Примечание: Возможно вы заметили, что CRL доставляются по незащищённому соединению и задумались, безопасно ли пользоваться такими списками? На самом деле всё в порядке. Поскольку каждый CRL подписывается выпускающим его УЦ, браузеры могут проверить его целостность. Фактически, если бы CRL распространялись через защищённое с помощью TLS соединение, браузеры бы могли столкнуться с проблемой курицы и яйца, пытаясь проверить статус отзыва сертификата, используемого самим сервером, распространяющим CRL!

Расширение Certificate Policies используется для указания политики, в соответствии с которой был выпущен сертификат. Например, именно здесь можно найти индикаторы extended validation (EV) (как в представленном ниже примере). Эти индикаторы представлены в форме уникальных идентификаторов объектов (OID), и они являются уникальными для выпускающего УЦ. Кроме того, это расширение часто содержит один или несколько пунктов Certificate Policy Statement (CPS), которые обычно являются либо веб-страницами, либо документами PDF.

X509v3 Certificate Policies:
    Policy: 2.16.840.1.114414.1.7.23.3
    CPS: http://certificates.starfieldtech.com/repository/

Расширение Authority Information Access (AIA) обычно содержит информацию, состоящую из двух важных частей. Во первых, в нём перечислены адреса серверов-ответчиков Online Certificate Status Protocol (OCSP) удостоверяющего центра, которые могут быть использованы для проверки статуса отзыва сертификата в режиме реального времени. Данное расширение также может содержать ссылку, по которой можно найти сертификат издателя (следующий сертификат в цепочке). В наши дни сертификаты серверов редко подписываются непосредственно доверенными корневыми сертификатами УЦ, и это означает, что администраторы сервера должны включать в свою конфигурацию один или несколько промежуточных сертификатов. Здесь легко допустить ошибку, и тогда сертификат сервера будет признан недействительным. Некоторые клиенты (например, Internet Explorer) будут использовать приведённую в данном расширении информацию для исправления неполных цепочек сертификатов, но так поступают далеко не все клиенты.

Authority Information Access:
    OCSP - URI:http://ocsp.starfieldtech.com/
    CA Issuers - URI:http://certificates.starfieldtech.com/repository/sf_intermediate.crt

Расширения Subject Key Identifier и Authority Key Identifier устанавливают уникальные идентификаторы ключа субъекта и ключа удостоверяющего центра соответственно. Значение, указанное в расширении Authority Key Identifier сертификата, должно совпадать со значением, указанным в расширении Subject Key Identifier того сертификата, которым подписан рассматриваемый сертификат. Эта информация очень полезна в процессе построения пути сертификации, когда клиент пытается найти все возможные пути от конечного сертификата (серверного) до доверенного корневого сертификата. Часто удостоверяющие центры используют один закрытый ключ с более чем одним сертификатом, и это поле позволяет программам надёжно определять, какой сертификат с каким ключом может быть сопоставлен. В реальном мире многие предоставляемые серверами цепочки сертификатов являются некорректными, но это часто остаётся незамеченным, поскольку браузеры способны находить альтернативные пути доверия.

X509v3 Subject Key Identifier:
    4A:AB:1C:C3:D3:4E:F7:5B:2B:59:71:AA:20:63:D6:C9:40:FB:14:F1
X509v3 Authority Key Identifier:
    keyid:49:4B:52:27:D1:1B:BC:F2:A1:21:6A:62:7B:51:42:7A:8A:D7:D5:56

Наконец, расширение Subject Alternative Name используется для перечисления имён хостов, для которых данный сертификат является действительным. Это расширение считается необязательным. Если оно отсутствует, клиенты возвращаются к использованию информации, предоставляемой в атрибуте Common Name (CN), являющемся частью поля Subject. Если это расширение присутствует, то содержимое поля CN в процессе валидации игнорируется.

X509v3 Subject Alternative Name:
    DNS:www.feistyduck.com, DNS:feistyduck.com

Преобразование ключей и сертификатов

Закрытые ключи и сертификаты могут храниться в различных форматах, а значит вам часто придётся преобразовывать их из одного формата в другой. Наиболее распространённые форматы:

Бинарный сертификат (DER)

Содержит сертификат X.509 в необработанном виде с использованием закодированных в DER структур ASN.1.

ASCII сертификат (сертификаты) (PEM)

Содержит сертификат DER в кодировке base64, перед которым помещается маркер -----BEGIN CERTIFICATE-----, а после — маркер -----END CERTIFICATE-----. Обычно в файле присутствует только один сертификат, хотя некоторые программы, в зависимости от контекста, допускают наличие более одного сертификата в файле. Например, в старых версиях веб-сервера Apache требовалось, чтобы сертификат сервера находился отдельно в одном файле, а все промежуточные сертификаты вместе — в другом файле.

Бинарный ключ (DER)

Содержит закрытый ключ в необработанном виде с использованием закодированных в DER структур ASN.1. OpenSSL создаёт ключи в своём собственном традиционном формате (SSLeay). Существует также альтернативный формат, называемый PKCS#8 (определён в RFC 5208), но он не получил широкого распространения. OpenSSL может преобразовывать как в формат PKCS#8, так и из него с помощью команды pkcs8.

ASCII ключ (PEM)

Содержит ключ DER в кодировке base64, иногда с дополнительными метаданными (например, указанием алгоритма, используемого для парольной защиты).

Сертификат (сертификаты) PKCS#7

Комплексный формат, предназначенный для транспортировки подписанных или зашифрованных данных, определён в RFC 2315. Файлы обычно имеют расширения .p7b и .p7c и, при необходимости, могут включать целиком цепочку сертификатов. Этот формат поддерживается Java-утилитой keytool.

Ключ и сертификат (сертификаты) PKCS#12 (PFX)

Комплексный формат, в котором может храниться в защищённом состоянии ключ сервера и полная цепочка сертификатов. Файлы обычно имеют расширения .p12 и .pfx. Этот формат обычно используется в продуктах Microsoft, но также может использоваться для клиентских сертификатов. В наши дни имя PFX используется как синоним для PKCS#12, хотя раньше (довольно давно) PFX указывал на другой формат (раннюю версию PKCS#12). Вряд ли вы сейчас встретите где-либо старую версию.

Преобразование в PEM и DER

Преобразование сертификата между форматами PEM и DER выполняется с помощью команды x509. Конвертация сертификата из PEM в DER:

$ openssl x509 -inform PEM -in fd.pem -outform DER -out fd.der

Конвертация сертификата из DER в PEM:

$ openssl x509 -inform DER -in fd.der -outform PEM -out fd.pem

Аналогичный синтаксис применяется для преобразования закрытых ключей между форматами DER и PEM, но в этом случае используются другие команды: rsa для ключей RSA, и dsa для ключей DSA.

Преобразование PKCS#12 (PFX)

Всего лишь одной команды достаточно для преобразования ключа и сертификатов, представленных в формате PEM, в PKCS#12. В следующем примере ключ (fd.key), сертификат (fd.crt) и промежуточные сертификаты (fd-chain.crt) конвертируются в один эквивалентный файл PKCS#12:

$ openssl pkcs12 -export 
    -name "My Certificate" 
    -out fd.p12 
    -inkey fd.key 
    -in fd.crt 
    -certfile fd-chain.crt
Enter Export Password: ****************
Verifying - Enter Export Password: ****************

С обратным преобразованием не всё так просто. Можно использовать одну команду, но в этом случае вы получите всё содержимое в одном файле:

$ openssl pkcs12 -in fd.p12 -out fd.pem -nodes

Теперь вам нужно открыть полученный файл fd.pem в вашем любимом редакторе и вручную разделить на отдельные файлы с ключом, сертификатом и промежуточными сертификатами. При этом вы заметите дополнительный контент перед каждым компонентом. Например:

Bag Attributes
    localKeyID: E3 11 E4 F1 2C ED 11 66 41 1B B8 83 35 D2 DD 07 FC DE 28 76
subject=/1.3.6.1.4.1.311.60.2.1.3=GB/2.5.4.15=Private Organization/serialNumber=06694169↩
/C=GB/ST=London/L=London/O=Feisty Duck Ltd/CN=www.feistyduck.com
issuer=/C=US/ST=Arizona/L=Scottsdale/O=Starfield Technologies, Inc./OU=http:/↩
/certificates.starfieldtech.com/repository/CN=Starfield Secure Certification Authority
-----BEGIN CERTIFICATE-----
MIIF5zCCBM+gAwIBAgIHBG9JXlv9vTANBgkqhkiG9w0BAQUFADCB3DELMAkGA1UE
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAj
[...]

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

Предупреждение: Конечный результат преобразования не должен содержать ничего, кроме закодированных ключа и сертификатов. Хотя некоторые инструменты достаточно умны, чтобы проигнорировать то, что не требуется, рассчитывать на это нельзя. Оставляя лишнюю информацию в файлах PEM, вы рискуете столкнуться со сложнодиагностируемыми проблемами.

Разделение пакета на компоненты можно переложить и на OpenSSL, но при этом придётся несколько раз вызывать команду pkcs12 (и каждый раз вводить пароль к пакету):

$ openssl pkcs12 -in fd.p12 -nocerts -out fd.key -nodes
$ openssl pkcs12 -in fd.p12 -nokeys -clcerts -out fd.crt
$ openssl pkcs12 -in fd.p12 -nokeys -cacerts -out fd-chain.crt

К сожалению, такой подход не приведёт к существенной экономии времени. Вам по-прежнему придётся проверять каждый файл, чтобы убедиться, что в нём находится именно то, что нужно, а также удалить метаданные.

Преобразование PKCS#7

Для преобразования из PEM в PKCS#7 используйте команду crl2pkcs7:

$ openssl crl2pkcs7 -nocrl -out fd.p7b -certfile fd.crt -certfile fd-chain.crt

Для преобразования из PKCS#7 в PEM используйте команду pkcs7 с параметром -print_certs:

openssl pkcs7 -in fd.p7b -print_certs -out fd.pem

Как и в случае с преобразованием из PKCS#12, нужно будет отредактировать файл fd.pem, очистив его и разделив на желаемые компоненты.

Конфигурация

В этом разделе мы обсудим две темы, относящиеся к развертыванию TLS. Первая — конфигурация наборов алгоритмов шифрования или наборов шифров, в которой вы указываете, какие именно из множества доступных в TLS наборов вы хотите использовать в процессе коммуникации. Эта тема важна, поскольку практически каждая программа, использующая OpenSSL, применяет её механизм конфигурации наборов. Это означает, что изучив однажды, каким образом настраиваются наборы шифров для одной программы, вы сможете повторно использовать эти знания где угодно. Вторая тема — измерение производительности низкоуровневых криптографических операций.

Выбор набора шифров

Распространённая задача в конфигурации сервера TLS — выбор того, какие наборы шифров будут поддерживаться. Для безопасной коммуникации программному обеспечению TLS необходимо определиться, какие именно криптографические примитивы использовать для достижения своих целей (например, обеспечения конфиденциальности). Это достигается путём выбора подходящего набора шифров, на основании которого принимается ряд решений о том, как будут выполняться аутентификация, обмен ключами, шифрование и другие операции. Программы, использующие в своей работе OpenSSL, обычно применяют тот же подход к настройке наборов шифров, что и OpenSSL, просто задавая те же параметры конфигурации. Например, в настройках сервера httpd от Apache конфигурация наборов шифров может выглядеть так:

SSLHonorCipherOrder On  
SSLCipherSuite "HIGH:!aNULL:@STRENGTH"

Параметр конфигурации в первой строке управляет приоритезацией наборов шифров (а также настраивает httpd на активный выбор наборов). Параметр конфигурации во второй строке управляет тем, какие наборы будут поддерживаться.

Создание хорошей конфигурации наборов может занять довольно много времени, при этом нужно учитывать множество деталей. Лучшим подходом в данном случае будет использование команды OpenSSL ciphers для определения того, какие именно наборы будут задействованы при выборе конкретной строки конфигурации.

Получение списка поддерживаемых наборов

Перед тем как продолжать, вам следует определиться с тем, какие наборы поддерживаются вашей инсталляцией OpenSSL. Для этого вызовите команду ciphers с параметром -v и указанием ключевых слов ALL:COMPLEMENTOFALL (очевидно, ALL в данном случае вовсе на означает «все»):

$ openssl ciphers -v 'ALL:COMPLEMENTOFALL'
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH Au=RSA   Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384        TLSv1.2 Kx=ECDH Au=RSA   Enc=AES(256)    Mac=SHA384
ECDHE-ECDSA-AES256-SHA384      TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256)    Mac=SHA384
ECDHE-RSA-AES256-SHA           SSLv3   Kx=ECDH Au=RSA   Enc=AES(256)    Mac=SHA1
[ещё 106 строк...]

Совет: При использовании OpenSSL 1.0.0 или более поздней версии, вы также можете применить параметр -V (в верхнем регистре), чтобы сделать вывод ещё подробнее. В этом режиме в вывод попадут также идентификаторы наборов, которые в любом случае полезно иметь под рукой. Например, OpenSSL не всегда использует для наборов шифров имена из RFC; в таких случаях вы должны использовать эти идентификаторы для обеспечения перекрёстной проверки.

В моём случае в вывод попали 111 наборов. Каждая строка содержит информацию об одном наборе в виде следующих полей:

  1. Имя набора

  2. Минимально допустимая версия протокола

  3. Алгоритм обмена ключами

  4. Алгоритм аутентификации

  5. Алгоритм и стойкость шифрования

  6. Алгоритм MAC (обеспечения целостности)

  7. Индикатор экспортного набора

Если изменить параметр ciphers на что-то отличное от ALL:COMPLEMENTOFALL, OpenSSL покажет только те наборы, которые будут соответствовать указанной настройке. Например, вы можете запросить вывод только тех наборов шифров, которые основаны на RC4, следующей командой:

$ openssl ciphers -v 'RC4'
ECDHE-RSA-RC4-SHA    SSLv3 Kx=ECDH       Au=RSA   Enc=RC4(128) Mac=SHA1
ECDHE-ECDSA-RC4-SHA  SSLv3 Kx=ECDH       Au=ECDSA Enc=RC4(128) Mac=SHA1
AECDH-RC4-SHA        SSLv3 Kx=ECDH       Au=None  Enc=RC4(128) Mac=SHA1
ADH-RC4-MD5          SSLv3 Kx=DH         Au=None  Enc=RC4(128) Mac=MD5
ECDH-RSA-RC4-SHA     SSLv3 Kx=ECDH/RSA   Au=ECDH  Enc=RC4(128) Mac=SHA1
ECDH-ECDSA-RC4-SHA   SSLv3 Kx=ECDH/ECDSA Au=ECDH  Enc=RC4(128) Mac=SHA1
RC4-SHA              SSLv3 Kx=RSA        Au=RSA   Enc=RC4(128) Mac=SHA1
RC4-MD5              SSLv3 Kx=RSA        Au=RSA   Enc=RC4(128) Mac=MD5
PSK-RC4-SHA          SSLv3 Kx=PSK        Au=PSK   Enc=RC4(128) Mac=SHA1
EXP-ADH-RC4-MD5      SSLv3 Kx=DH(512)    Au=None  Enc=RC4(40)  Mac=MD5  export
EXP-RC4-MD5          SSLv3 Kx=RSA(512)   Au=RSA   Enc=RC4(40)  Mac=MD5  export

В выводе будут содержаться все наборы, соответствующие заданному вами ограничению, даже если они небезопасны. Очевидно, что при настройке того или иного приложения вы должны тщательно выбирать строки конфигурации, чтобы активировать только то, что безопасно. Кроме того, порядок, в котором наборы появляются в выходных данных, имеет значение. Когда вы настраиваете свой TLS-сервер на активный выбор того набора шифров, который будет использоваться при соединении (что является лучшей практикой и рекомендуемым методом), приоритет будут иметь перечисленные вначале наборы шифров.

Ключевые слова

Ключевые слова набора шифров являются базовыми строительными блоками конфигурации наборов шифров. Каждое имя набора (например, RC4-SHA) является ключевым словом, с помощью которого выбирается ровно один набор. Все остальные ключевые слова отбирают группу наборов в соответствии с некоторыми критериями. Имена ключевых слов чувствительны к регистру символов. Конечно, можно было бы просто перенаправить вас на документацию OpenSSL для просмотра всего списка ключевых слов, но оказывается, что раздел по шифрам в ней не актуален: в нём не хватает нескольких последних добавлений. По этой причине я попытался задокументировать все ключевые слова в этом разделе.

Групповые ключевые слова — это сокращения для выбора часто используемых наборов шифров. Например, при наличии ключевого слова HIGH будут отобраны только очень стойкие наборы шифров.

Таблица 1.1. Групповые ключевые слова

Ключевое слово Значение
DEFAULT Список шифров по умолчанию. Определяется во время компиляции, для OpenSSL 1.0.0, как правило, ALL:!aNULL:!eNULL. При настройке отбора наборов шифров в приложении это ключевое слово должно быть указано первым в конфигурационной строке.
COMPLEMENTOFDEFAULT Шифры, входящие в ALL, но не задействованные по умолчанию. В настоящий момент это ADH. Обратите внимание, что это правило не распространяется на шифры eNULL, которые не входят в ALL (если это необходимо, используйте COMPLEMENTOFALL).
ALL Все наборы шифров, кроме шифров eNULL, которые должны быть включены явно.
COMPLEMENTOFALL Наборы шифров, не включённые в ALL, в настоящий момент это eNULL.
HIGH Наборы шифров «высокой» криптографической стойкости. В настоящий момент это означает наборы шифров с ключами, имеющими уровень криптостойкости более 128 бит, а также некоторые наборы шифров с уровнем криптостойкости в 128 бит.
MEDIUM Наборы шифров «средней» криптографической стойкости, в настоящий момент некоторые из них используют шифрование с уровнем криптостойкости 128 бит.
LOW Наборы шифров «низкой» криптографической стойкости. В настоящее время это те из них, в которых используются криптографические алгоритмы с уровнем криптостойкости 64 или 56 бит, за исключением экспортных наборов шифров. Небезопасные.
EXP, EXPORT Экспортные криптографические алгоритмы. Включая алгоритмы с уровнем криптостойкости 40 и 56 бит. Небезопасные.
EXPORT40 Экспортные алгоритмы с уровнем криптостойкости 40 бит. Небезопасные.
EXPORT56 Экспортные алгоритмы с уровнем криптостойкости 56 бит. Небезопасные.
TLSv1, SSLv3, SSLv2 Наборы шифров TLS 1.0, SSL 3 и SSL 2, соответственно.

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

Таблица 1.2. Ключевые слова алгоритмов хэширования

Ключевое слово Значение
MD5 Наборы шифров, использующие MD5. Устаревшие и небезопасные.
SHA, SHA1 Наборы шифров, использующие SHA1.
SHA256 (v1.0.0+) Наборы шифров, использующие SHA256.
SHA384 (v1.0.0+) Наборы шифров, использующие SHA384.

Примечание: С помощью ключевых слов алгоритмов хэширования выбираются только те наборы шифров, которые проверяют целостность данных на уровне протокола. В TLS 1.2 появилась поддержка аутентифицированного шифрования, представляющего собой механизм, который связывает шифрование с проверкой целостности. При использовании так называемых наборов AEAD (Authenticated Encryption with Associated Data), протоколу не требуется обеспечивать дополнительную проверку целостности. По этой причине вы не сможете использовать ключевые слова алгоритмов хэширования для выбора наборов AEAD (в настоящее время это наборы, в названии которых присутствует GCM). В названиях таких наборов используются суффиксы SHA256 и SHA384, но в данном случае они указывают на хэш-функции, используемые для построения используемой с набором псевдослучайной функции (что вносит некоторую путаницу).

С помощью ключевых слов аутентификации наборы выбираются на основании тех методов аутентификации, которые они используют. Сегодня для аутентификации практически во всех публичных сертификатах используется RSA. Со временем мы, вероятно, увидим очень медленный прирост использования сертификатов Elliptic Curve (ECDSA).

Табица 1.3. Ключевые слова аутентификации

Ключевое слово Значение
aDH Наборы шифров, фактически использующие аутентификацию DH, то есть сертификаты содержат ключи DH. (v1.0.2+)
aDSS, DSS Наборы шифров, использующие аутентификацию DSS, то есть сертификаты содержат ключи DSS.
aECDH (v1.0.0+) Наборы шифров, использующие аутентификацию ECDH.
aECDSA (v1.0.0+) Наборы шифров, использующие аутентификацию ECDSA.
aNULL Наборы шифров, не предлагающие аутентификацию. В настоящее время это анонимные алгоритмы DH. Небезопасные.
aRSA Наборы шифров, использующие аутентификацию RSA, то есть сертификаты содержат ключи RSA.
PSK Наборы шифров, использующие аутентификацию PSK (Pre-Shared Key).
SRP Наборы шифров, использующие аутентификацию SRP (Secure Remote Password).

С помощью ключевых слов обмена ключами наборы выбираются на основании алгоритма обмена ключами. Когда речь заходит о наборах с эфемерным обменом по протоколу Диффи-Хеллмана, разработчики OpenSSL непоследовательны в именовании наборов и ключевых слов. В названиях наборов эфемерные алгоритмы обмена ключами, как правило обозначаются буквой E на конце названия алгоритма (например, ECDHE-RSA-RC4-SHA и DHE-RSA-AES256-SHA), а в ключевых словах отбора буква E указывается в начале (например, EECDH и EDH). Чтобы усугубить ситуацию, в некоторых старых наборах шифров буква E ставится в начале названия алгоритма обмена ключами (например, EDH-RSA-DES-CBC-SHA).

Таблица 1.4. Ключевые слова обмена ключами

Ключевое слово Значение
ADH Наборы шифров с анонимным обменом DH. Небезопасные.
AECDH (v1.0.0+) Наборы шифров с анонимным обменом ECDH. Небезопасные.
DH Наборы шифров, использующие обмен DH (в том числе эфемерный и анонимный обмен DH).
ECDH (v1.0.0+) Наборы шифров, использующие обмен ECDH (в том числе эфемерный и анонимный обмен ECDH).
EDH (v1.0.0+) Наборы шифров, использующие эфемерное согласование ключей DH.
EECDH (v1.0.0+) Наборы шифров, использующие эфемерный обмен ECDH.
kECDH (v1.0.0+) Наборы шифров, использующие эфемерное согласование ключей ECDH.
kEDH Наборы шифров, использующие эфемерное согласование ключей DH (включая анонимный обмен DH).
kEECDH (v1.0.0+) Наборы шифров, использующие эфемерное согласование ключей ECDH (включая анонимный обмен ECDH).
kRSA, RSA Наборы шифров, использующие алгоритм обмена ключами RSA.

С помощью ключевых слов шифров наборы выбираются на основании используемых ими шифров.

Таблица 1.5. Ключевые слова шифров

Ключевое слово Значение
3DES Наборы шифров, использующие Triple DES. Устаревшие и небезопасные.
AES Наборы шифров, использующие AES.
AESGCM (v1.0.0+) Наборы шифров, использующие AES GCM.
CAMELLIA Наборы шифров, использующие Camellia. Устаревшие.
DES Наборы шифров, использующие Single DES. Устаревшие и небезопасные.
eNULL, NULL Наборы шифров не использующие шифрование. Небезопасные.
IDEA Наборы шифров, использующие IDEA. Устаревшие.
RC2 Наборы шифров, использующие RC2. Устаревшие и небезопасные.
RC4 Наборы шифров, использующие RC4. Небезопасные.
SEED Наборы шифров, использующие SEED. Устаревшие.

Остаётся ряд наборов, которые не вписываются ни в одну из рассмотренных ранее категорий. Основная их часть связана со стандартами ГОСТ, которые актуальны для стран, входящих в Содружество Независимых Государств, образовавшееся после распада Советского Союза.

Таблица 1.6. Прочие ключевые слова

Ключевое слово Значение
@STRENGTH Сортирует текущий список наборов шифров в порядке длины ключа алгоритма шифрования..
aGOST Наборы шифров, использующие аутентификацию GOST R 34.10 (как 2001, так и 94). Для работы требуется модуль обеспечения совместимости с ГОСТ.
aGOST01 Наборы шифров, использующие аутентификацию GOST R 34.10-2001.
aGOST94 Наборы шифров, использующие аутентификацию GOST R 34.10-94. Устаревшие. Вместо них используйте GOST R 34.10-2001.
kGOST Наборы шифров, использующие обмен ключами VKO 34.10, определённый в RFC 4357.
GOST94 Наборы шифров, использующие HMAC, основанный на GOST R 34.11-94.
GOST89MAC Наборы шифров, использующие GOST 28147-89 MAC вместо HMAC.

Комбинирование ключевых слов

Чаще всего вы будете использовать ключевые слова по отдельности, но также возможно комбинировать их, чтобы отбирать только те наборы, которые удовлетворяют сразу нескольким требованиям. Это делается путём соединения двух или более ключевых слов символом +. В следующем примере мы выбираем наборы, использующие RC4 и SHA:

$ openssl ciphers -v 'RC4+SHA'
ECDHE-RSA-RC4-SHA    SSLv3 Kx=ECDH       Au=RSA   Enc=RC4(128) Mac=SHA1
ECDHE-ECDSA-RC4-SHA  SSLv3 Kx=ECDH       Au=ECDSA Enc=RC4(128) Mac=SHA1
AECDH-RC4-SHA        SSLv3 Kx=ECDH       Au=None  Enc=RC4(128) Mac=SHA1
ECDH-RSA-RC4-SHA     SSLv3 Kx=ECDH/RSA   Au=ECDH  Enc=RC4(128) Mac=SHA1
ECDH-ECDSA-RC4-SHA   SSLv3 Kx=ECDH/ECDSA Au=ECDH  Enc=RC4(128) Mac=SHA1
RC4-SHA              SSLv3 Kx=RSA        Au=RSA   Enc=RC4(128) Mac=SHA1
PSK-RC4-SHA          SSLv3 Kx=PSK        Au=PSK   Enc=RC4(128) Mac=SHA1

Построение списков наборов шифров

Ключевой концепцией при построении конфигурации наборов шифров является концепция текущего списка наборов. Первоначально этот список всегда пуст, в нём нет ни одного набора шифров, но каждое ключевое слово, добавляемое вами в строку конфигурации, тем или иным способом меняет этот список. По умолчанию новые наборы добавляются в конец списка. Например, чтобы выбрать все наборы, использующие шифрование RC4 и AES, применяется такая строка конфигурации:

$ openssl ciphers -v 'RC4:AES'

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

$ openssl ciphers -v 'RC4 AES'

Модификаторы ключевых слов

Модификаторы ключевых слов — это символы, которые можно поместить перед ключевым словом для того, чтобы изменить действие по умолчанию (добавление в список) на что-то другое. Поддерживаются следующие действия:

Добавление в конец

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

Удаление (-)

Удаляет все соответствующие наборы из текущего списка. Потенциально позволяет некоторым другим ключевым словам повторно ввести эти наборы позже.

Удаление навсегда (!)

Удаляет все соответствующие наборы из текущего списка и предотвращает дальнейшее их добавление в помощью других ключевых слов. Этот модификатор полезен для указания тех наборов, которые вы не хотите использовать ни при каких обстоятельствах; тем самым упрощается дальнейший отбор и предотвращаются ошибки.

Перемещение в конец (+)

Перемещает все соответствующие наборы в конец текущего списка. Работает только для тех наборов, которые уже в списке; новые наборы в список не добавляются. Этот модификатор полезен, если вы хотите, чтобы некоторые более слабые наборы были включены, но отдаёте предпочтение более сильным. Например, строка RC4:+MD5 включает все наборы RC4, но помещает те из них, которые основаны на MD5, в конец списка.

Сортировка

Ключевое слово @STRENGTH отличается от других ключевых слов (не зря же в его названии есть символ @): оно не добавляет и не удаляет никаких наборов, но сортирует их в порядке уменьшения стойкости шифра. Автоматическая сортировка — интересная идея, но она имеет смысл только в идеальном мире, в котором наборы шифров можно было бы сопоставить лишь по формальному уровню криптостойкости шифра.

Возьмём для примера следующую конфигурацию наборов шифров:

$ openssl ciphers -v 'DES-CBC-SHA DES-CBC3-SHA RC4-SHA AES256-SHA @STRENGTH'
AES256-SHA                     SSLv3   Kx=RSA  Au=RSA   Enc=AES(256)    Mac=SHA1
DES-CBC3-SHA                   SSLv3   Kx=RSA  Au=RSA   Enc=3DES(168)   Mac=SHA1
RC4-SHA                        SSLv3   Kx=RSA  Au=RSA   Enc=RC4(128)    Mac=SHA1
DES-CBC-SHA                    SSLv3   Kx=RSA  Au=RSA   Enc=DES(56)     Mac=SHA1

В теории вывод команды отсортирован в порядке стойкости шифров. На практике вам, скорее всего, захочется более детально контролировать этот порядок:

  • Например, AES256-SHA (набор CBC) уязвим для атак BEAST при использовании с протоколом TLS 1.0 и более ранними версиями. Если вы хотите уменьшить вероятность атаки BEAST на стороне сервера, вы предпочтёте отдать приоритет пакету RC4-SHA, который не подвержен этой проблеме.

  • Уровень криптостойкости 3DES только номинально оценивается в 168 бит; так называемая атака встреча посередине (meet-in-the-middle) уменьшает его стойкость до 112 бит9, а дальнейшие оптимизации подбора и вовсе снижают стойкость до 108 бит10. Этот факт делает DES-CBC3-SHA хуже 128-битных наборов шифров. Строго говоря, трактовка 3DES как 168-битного шифра — это баг в OpenSSL, который был исправлен в более поздних версиях.

Обработка ошибок

При работе со своей конфигурацией вы можете столкнуться с двумя типами ошибок. Одни из них возникают в результате опечатки или попытки использовать несуществующее ключевое слово:

$ openssl ciphers -v '@HIGH'
Error in cipher list
140460843755168:error:140E6118:SSL routines:SSL_CIPHER_PROCESS_RULESTR:invalid ↩
command:ssl_ciph.c:1317:

Вывод, конечно, загадочный, но в нём содержится сообщение об ошибке.

Другая возможная ошибка состоит в том, что вы получите пустой список наборов шифров. В этом случае вывод будет примерно такой:

$ openssl ciphers -v 'SHA512'
Error in cipher list
140202299557536:error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl↩
_lib.c:1312:

Собираем всё вместе

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

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

  1. Используются только стойкие шифры с фактическим уровнем криптостойкости 128 бит и выше (это исключает 3DES).

  2. Используются только наборы, обеспечивающие строгую аутентификацию (это исключает анонимные и экспортные наборы).

  3. Не используются любые наборы, полагающиеся на уязвимые исходные алгоритмы (например, MD5).

  4. Реализуется надежная поддержка прямой секретности, независимо от того, какие ключи и протоколы применяются. С этим требованием связано небольшое снижение производительности, потому что не будет возможности использовать быстрый обмен ключами RSA. Чтобы минимизировать это снижение, мы будем отдавать приоритет ECDHE, которые значительно быстрее, чем DHE.

  5. Предпочтение отдаётся ECDSA над RSA. Это требование имеет смысл только при использовании в системе двух вариантов шифрования. То есть мы хотим использовать более быстрые операции ECDSA там, где это только возможно, но откатываться на RSA при взаимодействии с клиентами, которые ещё не поддерживают ECDSA.

  6. При работе с клиентами TLS 1.2 предпочтение отдаётся наборам AES GCM, обеспечивающим наилучший уровень безопасности, который только может предложить TLS.

  7. Поскольку недавно выяснилось, что шифры RC4 слабее, чем это считалось ранее11, поместим их в конец нашего списка. Это почти также эффективно, как и полное их отключение. Хотя BEAST всё ещё может быть проблемой в некоторых ситуациях, предполагается, что о минимизации этой атаки позаботились на стороне клиента.

Обычно лучший подход — начать с полного удаления всех компонентов и наборов, которые вы не хотите использовать; это уменьшает беспорядок и гарантирует, что нежелательные наборы не будут случайно добавлены в конфигурацию по ошибке.

Слабые наборы могут быть идентифицированы следующими ключевыми словами:

  • aNULL; без аутентификации

  • eNULL; без шифрования

  • LOW; наборы с низкой стойкостью

  • 3DES; фактическая стойкость — 108 бит

  • MD5; наборы, использующие MD5

  • EXP; устаревшие экспортные наборы

Для уменьшения количества выводимых наборов я собираюсь полностью устранить все наборы DSA, PSK, SRP и ECDH, поскольку они используются крайне редко. Также я удалю шифры IDEA и SEED, которые устарели, но все еще могут поддерживаться OpenSSL. В своей конфигурации я также не буду использовать CAMELLIA, потому что он медленнее и не так хорошо поддерживается, как AES (например, на практике нет вариантов GCM или ECDHE).

!aNULL !eNULL !LOW !3DES !MD5 !EXP !DSS !PSK !SRP !kECDH !CAMELLIA !IDEA !SEED

Теперь мы можем сосредоточиться на том, чего хотим достичь. Поскольку нашим приоритетом является прямая секретность, мы можем начать с ключевых слов kEECDH и kEDH:

kEECDH kEDH !aNULL !eNULL !LOW !3DES !MD5 !EXP !DSS !PSK !SRP !kECDH !CAMELLIA !IDEA ↩
!SEED

Если протестировать эту конфигурацию, обнаружится, что наборы RSA перечислены первыми, хотя мы хотели бы видеть первыми ECDSA:

ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH Au=RSA   Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384        TLSv1.2 Kx=ECDH Au=RSA   Enc=AES(256)    Mac=SHA384
ECDHE-ECDSA-AES256-SHA384      TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256)    Mac=SHA384
ECDHE-RSA-AES256-SHA           SSLv3   Kx=ECDH Au=RSA   Enc=AES(256)    Mac=SHA1
ECDHE-ECDSA-AES256-SHA         SSLv3   Kx=ECDH Au=ECDSA Enc=AES(256)    Mac=SHA1
ECDHE-RSA-AES128-GCM-SHA256    TLSv1.2 Kx=ECDH Au=RSA   Enc=AESGCM(128) Mac=AEAD
[...]

Чтобы это исправить, поместим kEECDH+ECDSA в начало конфигурации:

kEECDH+ECDSA kEECDH kEDH !aNULL !eNULL !LOW !3DES !MD5 !EXP !DSS !PSK !SRP !kECDH ↩
!CAMELLIA !IDEA !SEED

Следующая проблема — то, что более старые наборы (SSL 3) перемешаны с более новыми (TLS 1.2). Для обеспечения максимальной безопасности хотелось бы, чтобы клиенты, поддерживающие TLS 1.2, всегда согласовывали именно TLS 1.2. Чтобы переместить более старые наборы в конец списка, я использую ключевое слово +SHA (наборы TLS 1.2 всегда используют либо SHA256, либо SHA384, то есть под это условие они не попадут):

kEECDH+ECDSA kEECDH kEDH +SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !DSS !PSK !SRP !kECDH ↩
!CAMELLIA !IDEA !SEED

В таком виде конфигурация практически полностью отвечает нашим требованиям. Осталось поместить оставшиеся ещё неохваченными безопасные наборы в конец списка; сделаем это с помощью ключевого слова HIGH. Кроме того, нужно удостовериться, что наборы RC4 являются последними; с помощью ключевого слова +RC4 мы переместим уже существующие наборы RC4 в конец списка, а с помощью ключевого слова RC4 добавим туда же ещё незадействованные наборы RC4:

kEECDH+ECDSA kEECDH kEDH HIGH +SHA +RC4 RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !DSS ↩
!PSK !SRP !kECDH !CAMELLIA !IDEA !SEED

Давайте рассмотрим окончательный результат, который состоит из 28 наборов. В первой группе у нас наборы TLS 1.2:

ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384      TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256)    Mac=SHA384
ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-SHA256      TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128)    Mac=SHA256
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH Au=RSA   Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384        TLSv1.2 Kx=ECDH Au=RSA   Enc=AES(256)    Mac=SHA384
ECDHE-RSA-AES128-GCM-SHA256    TLSv1.2 Kx=ECDH Au=RSA   Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256        TLSv1.2 Kx=ECDH Au=RSA   Enc=AES(128)    Mac=SHA256
DHE-RSA-AES256-GCM-SHA384      TLSv1.2 Kx=DH   Au=RSA   Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-SHA256          TLSv1.2 Kx=DH   Au=RSA   Enc=AES(256)    Mac=SHA256
DHE-RSA-AES128-GCM-SHA256      TLSv1.2 Kx=DH   Au=RSA   Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-SHA256          TLSv1.2 Kx=DH   Au=RSA   Enc=AES(128)    Mac=SHA256
AES256-GCM-SHA384              TLSv1.2 Kx=RSA  Au=RSA   Enc=AESGCM(256) Mac=AEAD
AES256-SHA256                  TLSv1.2 Kx=RSA  Au=RSA   Enc=AES(256)    Mac=SHA256
AES128-GCM-SHA256              TLSv1.2 Kx=RSA  Au=RSA   Enc=AESGCM(128) Mac=AEAD
AES128-SHA256                  TLSv1.2 Kx=RSA  Au=RSA   Enc=AES(128)    Mac=SHA256

Сначала идут наборы ECDHE, затем — DHE, а за ними уже все остальные наборы TLS 1.2. В каждой из подгрупп приоритет имеют ECDSA и GCM.

Во второй группе представлены наборы, которые будут использоваться клиентами TLS 1.0. Приоритеты здесь такие же, как и в первой группе:

ECDHE-ECDSA-AES256-SHA         SSLv3   Kx=ECDH Au=ECDSA Enc=AES(256)    Mac=SHA1
ECDHE-ECDSA-AES128-SHA         SSLv3   Kx=ECDH Au=ECDSA Enc=AES(128)    Mac=SHA1
ECDHE-RSA-AES256-SHA           SSLv3   Kx=ECDH Au=RSA   Enc=AES(256)    Mac=SHA1
ECDHE-RSA-AES128-SHA           SSLv3   Kx=ECDH Au=RSA   Enc=AES(128)    Mac=SHA1
DHE-RSA-AES256-SHA             SSLv3   Kx=DH   Au=RSA   Enc=AES(256)    Mac=SHA1
DHE-RSA-AES128-SHA             SSLv3   Kx=DH   Au=RSA   Enc=AES(128)    Mac=SHA1
DHE-RSA-SEED-SHA               SSLv3   Kx=DH   Au=RSA   Enc=SEED(128  ) Mac=SHA1
AES256-SHA                     SSLv3   Kx=RSA  Au=RSA   Enc=AES(256)    Mac=SHA1
AES128-SHA                     SSLv3   Kx=RSA  Au=RSA   Enc=AES(128)    Mac=SHA1

И наконец, наборы RC4 представлены в конце списка:

ECDHE-ECDSA-RC4-SHA            SSLv3   Kx=ECDH Au=ECDSA Enc=RC4(128)    Mac=SHA1
ECDHE-RSA-RC4-SHA              SSLv3   Kx=ECDH Au=RSA   Enc=RC4(128)    Mac=SHA1
RC4-SHA                        SSLv3   Kx=RSA  Au=RSA   Enc=RC4(128)    Mac=SHA1

Рекомендуемая конфигурация

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

Принципы проектирования для всех конфигураций здесь, в основном, те же, что и в предыдущем разделе, но я собираюсь сделать пару изменений для достижения лучшей производительности. Во-первых, я собираюсь поместить наборы, шифры которых имеют уровень криптостойкости 128 бит, в начало списка. Хотя 256-битные наборы обеспечивают некоторое повышение безопасности, для большинства сайтов оно не имеет смысла и сопровождается снижением производительности. Во-вторых, я собираюсь отдать предпочтение наборам с HMAC-SHA, а не с HMAC-SHA256 и HMAC-SHA384, которые гораздо медленнее и также не обеспечивают значительного повышения безопасности.

Кроме того, я собираюсь поменять подход к конфигурированию наборов, отказавшись от использования ключевых слов в пользу непосредственно имён наборов. Концептуально, использование ключевых слов — неплохая идея: вы определяете свои требования безопасности, а библиотека делает всё остальное, и вам не приходится вдаваться в подробности о тех наборах, которые в итоге будут использоваться. К сожалению, на практике такой подход уже неэффективен, поскольку мы стали довольно разборчивы в том, какие наборы хотим включить и в каком порядке.

Использовать имена наборов в конфигурации также просто: вы просто перечисляете наборы, которые хотите применять. И когда вы будете просматривать чью-либо конфигурацию, вам сразу станет понятно, какие именно наборы используются, нет необходимости пропускать настройки через OpenSSL.

Вот моя стартовая конфигурация по умолчанию, спроектированная для обеспечения высокого уровня безопасности и хорошей производительности:

ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES128-SHA
ECDHE-ECDSA-AES256-SHA
ECDHE-ECDSA-AES128-SHA256
ECDHE-ECDSA-AES256-SHA384
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-SHA
ECDHE-RSA-AES256-SHA
ECDHE-RSA-AES128-SHA256
ECDHE-RSA-AES256-SHA384
DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES128-SHA
DHE-RSA-AES256-SHA
DHE-RSA-AES128-SHA256
DHE-RSA-AES256-SHA256

Примечание: Начиная с ветки 1.1.x, OpenSSL поддерживает наборы ChaCha20/Poly130512. Эти наборы с проверкой аутентификации (например, ECDHE-ECDSA-CHACHA20-POLY1305 и ECDHE-RSA-CHACHA20-POLY1305) обеспечивают высокий уровень безопасности и альтернативу наборам AES. Сообщается, что они обеспечивают более высокую производительность для пользователей мобильных устройств, но наборы AES GCM всё ещё работают быстрее на современных настольных компьютерах, где доступно аппаратное ускорение. Поместите их в начало списка или сразу за вашими наборами GCM, в зависимости от того, какая часть вашей аудитории использует мобильные устройства. Во время написания этого материала OpenSSL ещё не поддерживал одинаковый уровень предпочтения наборов (в отличие, например, от BoringSSL), что позволяло бы клиенту самому выбрать между наборами AES-GCM и ChaCha20.

В этой конфигурации используются только наборы с поддержкой прямой секретности и обеспечением стойкого шифрования. Большинство современных браузеров и других клиентов смогут установить соединение, но некоторые очень старые клиенты, возможно, нет. Например, старые версии Internet Explorer, работающие на Windows XP, будут выдавать ошибку.

Если вам действительна нужна поддержка очень старых клиентов (и только в этом случае), рассмотрите вариант добавления в конец списка следующих наборов шифров:

EDH-RSA-DES-CBC3-SHA
AES128-SHA
AES256-SHA
DES-CBC3-SHA
ECDHE-RSA-RC4-SHA
RC4-SHA

Большинство из этих старых наборов используют обмен ключами RSA, а значит не обеспечивают прямую секретность. Предпочтение отдаётся шифрам AES, но 3DES и (небезопасные) RC4 также поддерживаются для максимальной совместимости с как можно большим числом клиентов. Если нельзя обойтись без использования RC4, предпочтение должно отдаваться наборам с ECDHE, обеспечивающим прямую секретность.

Производительность

Как вы, скорее всего, знаете, скорость вычислений является существенным ограничивающим фактором для любой криптографической операции. В OpenSSL есть встроенный инструмент тестирования производительности, который вы можете использовать для получения представления о возможностях и ограничениях системы. Запустить тестирование можно с помощью команды speed.

Если выполнить команду speed без параметров, OpenSSL сгенерирует большое количество выводных данных, но полезного в них будет немного. Лучше тестировать только те алгоритмы, которые вас непосредственно интересуют. Например, для защиты веб-сервера вам могут понадобиться алгоритмы RC4, AES, RSA, ECDH и SHA:

$ openssl speed rc4 aes rsa ecdh sha

Вывод команды состоит из трёх частей. В первой части показан номер версии OpenSSL и параметры компиляции, с которым был собран этот экземпляр OpenSSL. Эта информация полезна, если вы тестируете различные версии OpenSSL с отличающимися параметрами компиляции:

OpenSSL 0.9.8k 25 Mar 2009
built on: Wed May 23 00:02:00 UTC 2012
options:bn(64,64) md2(int) rc4(ptr,char) des(idx,cisc,16,int) aes(partial) ↩
blowfish(ptr2)
compiler: cc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN ↩
-DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall -DMD32_REG_T=int ↩
-DOPENSSL_BN_ASM_MONT -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM
available timing options: TIMES TIMEB HZ=100 [sysconf value]
timing function used: times
The 'numbers' are in 1000s of bytes per second processed.

Во второй части приводятся результаты тестирования симметричной криптографии (хэш-функций и криптографических алгоритмов):

type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
sha1             29275.44k    85281.86k   192290.28k   280526.68k   327553.12k
rc4             160087.81k   172435.03k   174264.75k   176521.50k   176700.62k
aes-128 cbc      90345.06k   140108.84k   170027.92k   179704.12k   182388.44k
aes-192 cbc     104770.95k   134601.12k   148900.05k   152662.30k   153941.11k
aes-256 cbc      95868.62k   116430.41k   124498.19k   127007.85k   127430.81k
sha256           23354.37k    54220.61k    99784.35k   126494.48k   138266.71k
sha512           16022.98k    64657.88k   113304.06k   178301.77k   214539.99k

Наконец, в третьей части результаты тестирования асимметричной криптографии:

                  sign    verify    sign/s verify/s
rsa  512 bits 0.000120s 0.000011s   8324.9  90730.0
rsa 1024 bits 0.000569s 0.000031s   1757.0  31897.1
rsa 2048 bits 0.003606s 0.000102s    277.3   9762.0
rsa 4096 bits 0.024072s 0.000376s     41.5   2657.4
                              op      op/s
 160 bit ecdh (secp160r1)   0.0003s   2890.2
 192 bit ecdh (nistp192)   0.0006s   1702.9
 224 bit ecdh (nistp224)   0.0006s   1743.5
 256 bit ecdh (nistp256)   0.0007s   1513.3
 384 bit ecdh (nistp384)   0.0015s    689.6
 521 bit ecdh (nistp521)   0.0029s    340.3
 163 bit ecdh (nistk163)   0.0009s   1126.2
 233 bit ecdh (nistk233)   0.0012s    818.5
 283 bit ecdh (nistk283)   0.0028s    360.2
 409 bit ecdh (nistk409)   0.0060s    166.3
 571 bit ecdh (nistk571)   0.0130s     76.8
 163 bit ecdh (nistb163)   0.0009s   1061.3
 233 bit ecdh (nistb233)   0.0013s    755.2
 283 bit ecdh (nistb283)   0.0030s    329.4
 409 bit ecdh (nistb409)   0.0067s    149.7
 571 bit ecdh (nistb571)   0.0146s     68.4

Чем может быть полезен вывод этой команды? Вы можете сравнить как опции компиляции влияют на скорость, или насколько отличается скорость работы разных версий OpenSSL на одной платформе. Например, предыдущие результаты получены на реальном сервере с использованием OpenSSL 0.9.8k (с исправлениями от поставщика дистрибутива). Я планирую перейти на OpenSSL 1.0.1h, поскольку хочу иметь поддержку TLS 1.1 и TLS 1.2; окажет ли это какое-либо влияние на производительность? Для тестирования я скачал и скомпилировал OpenSSL 1.0.1h. Давайте посмотрим:

$ ./openssl-1.0.1h speed rsa
[...]
OpenSSL 1.0.1h 5 Jun 2014
built on: Thu Jul  3 18:30:06 BST 2014
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
compiler: gcc -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H ↩
-Wa,--noexecstack -m64 -DL_ENDIAN -DTERMIO -O3 -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN↩
_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512↩
_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
                  sign    verify    sign/s verify/s
rsa  512 bits 0.000102s 0.000008s   9818.0 133081.7
rsa 1024 bits 0.000326s 0.000020s   3067.2  50086.9
rsa 2048 bits 0.002209s 0.000068s    452.8  14693.6
rsa 4096 bits 0.015748s 0.000255s     63.5   3919.4

Как видите, для моего варианта использования (2048-битный ключ RSA) OpenSSL 1.0.1h почти в два раза быстрее на этом сервере: производительность возросла в 277 до 450 электронных подписей в секунду. Это означает, что в случае обновления я получу более высокую производительность. Замечательная новость!

Использовать подобные результаты тестирования для оценки производительности будущего развертывания не совсем объективно из-за большого числа факторов, влияющих на производительность в реальной жизни. Более того, многие из этих факторов лежат за пределами TLS (например, настройки HTTP Keep-Alive, кэширование и т.д.). В лучшем случае вы можете использовать эти цифры только для приблизительной оценки.

Также нельзя упускать из виду кое-что ещё. По умолчанию команда speed будет использовать только один процесс. У большинства серверов несколько ядер процессора, поэтому для определения того, как много операций TLS поддерживается сервером в целом, нужно указать в команде speed использовать несколько экземпляров в параллельном режиме. Это достигается с помощью параметра -multi. У моего сервера четыре ядра, поэтому я собираюсь использовать такую команду:

$ openssl speed -multi 4 rsa
[...]
OpenSSL 0.9.8k 25 Mar 2009
built on: Wed May 23 00:02:00 UTC 2012
options:bn(64,64) md2(int) rc4(ptr,char) des(idx,cisc,16,int) aes(partial) ↩
blowfish(ptr2)
compiler: cc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN ↩
-DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -O3 -Wa,--noexecstack -g -Wall -DMD32_REG_T=int ↩
-DOPENSSL_BN_ASM_MONT -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM
available timing options: TIMES TIMEB HZ=100 [sysconf value]
timing function used:
                  sign    verify    sign/s verify/s
rsa  512 bits 0.000030s 0.000003s  33264.5 363636.4
rsa 1024 bits 0.000143s 0.000008s   6977.9 125000.0
rsa 2048 bits 0.000917s 0.000027s   1090.7  37068.1
rsa 4096 bits 0.006123s 0.000094s    163.3  10652.6

Как и ожидалось, производительность возросла почти в четыре раза (я опять сужу по количеству сформированных электронных подписей RSA в секунду, поскольку эта выполняемая на сервере криптографическая операция потребляет больше всего ресурсов процессора и всегда является самым узким местом). Результат в 1090 подписей в секунду говорит о том, что этот сервер может обработать около 1000 новых TLS-соединений в секунду. В моем случае этого достаточно, даже с хорошим запасом прочности. Поскольку у меня на сервере также включено возобновление сеанса, я уверен, что он сможет поддерживать более 1000 TLS-соединений в секунду. Надеюсь, что когда-нибудь на этом сервере будет столько трафика, чтобы мне пришлось беспокоиться о производительности TLS.

Другая причина, по которой вам не следует слишком уж доверять выводу команды speed, — то, что по умолчанию она не использует наиболее быстрые из доступных реализаций шифров. В некотором смысле, вывод по умолчанию не отражает истинного состояния дел. Например, на серверах, поддерживающих установку инструкции AES-NI для ускорения вычислений AES, эта функция не будет использоваться по умолчанию при тестировании:

$ openssl speed aes-128-cbc
[...]
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
aes-128 cbc      67546.70k    74183.00k    69278.82k   155942.87k   156486.38k

Для активации аппаратного ускорения нужно использовать параметр командной строки -evp:

$ openssl speed -evp aes-128-cbc
[...]
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
aes-128-cbc     188523.36k   223595.37k   229763.58k   203658.58k   206452.14k

Создание частного удостоверяющего центра

Если вы хотите настроить свой собственный УЦ, всё необходимое для этого уже включено в OpenSSL. Пользовательский интерфейс этой задачи основан исключительно на командной строке и потому не очень удобен для пользователя, но, возможно, это и к лучшему. Прохождение процесса шаг за шагом очень познавательно, поскольку заставляет задуматься о каждом аспекте и даже о мельчайших деталях.

Образовательный аспект настройки частного УЦ — главная причина, по которой я бы рекомендовал этим заняться, но есть и другие. УЦ на базе OpenSSL, каким бы кустарным на первый взгляд он ни казался, вполне может удовлетворить потребности отдельного человека или небольшой группы. К примеру, в экспериментальной среде значительно лучше использовать частный УЦ, чем повсеместно пользоваться самоподписанными сертификатами. Кроме того, клиентские сертификаты, служащие для обеспечения двухфакторной аутентификации, могут значительно повысить безопасность ваших конфиденциальных веб-приложений.

Самая большая трудность в запуске частного УЦ состоит даже не в качественной настройке всего, а в обеспечении безопасности инфраструктуры. Например, корневой ключ должен храниться автономно (оффлайн), поскольку безопасность всего УЦ зависит от его конфиденциальности. С другой стороны, CRL и сертификаты ответчиков OCSP должны регулярно обновляться, что невозможно без применения корневого ключа.

По ходу работы с данным разделом вы создадите два конфигурационных файла: один для управления корневым УЦ (root-ca.conf), а другой для управления подчинённым УЦ (sub-ca.conf). Их можно создавать с нуля, следуя представленным здесь инструкциям, а можно скачать шаблоны этих конфигурационных файлов из моего GitHub-репозитория13. В последнем случае вы сэкономите какое-то время, однако при ручном составлении понимание процесса будет лучше.

Основной функционал и ограничения

Далее в этом разделе мы будем создавать частный УЦ, аналогичный по своей структуре публичным УЦ. Будет создан один корневой УЦ, от которого можно будет создавать подчинённые УЦ. Информацию об отзыве сертификатов мы будем предоставлять через CRL и ответчики OCSP. Для поддержания автономности корневого УЦ у ответчиков OCSP будут свои собственные идентификационные сущности. Это не самый простой частный удостоверяющий центр, который можно было бы организовать, но зато его защита будет построена правильным образом. В качестве бонуса мы сделаем подчинённый УЦ технически ограниченным, то есть ему будет разрешено выдавать сертификаты только для разрешённых имён хостов.

По окончании развёртывания УЦ корневой сертификат должен быть безопасно распространён среди всех предполагаемых клиентов. После этого можно начинать выпуск клиентских и серверных сертификатов. Основным ограничением данного варианта установки будет то, что ответчик OCSP предназначен главным образом для тестирования и не рассчитан на высокие нагрузки.

Создание корневого УЦ

Создание нового УЦ состоит из нескольких этапов: настройка, создание структуры каталогов и инициализация значимых для УЦ файлов, и, наконец, генерация корневых ключа и сертификата. В данном разделе мы рассмотрим весь этот процесс, а также основные операции, выполняемые в рамках УЦ.

Конфигурация корневого УЦ

Перед тем, как мы сможем приступить к собственно созданию УЦ, нам необходимо подготовить конфигурационный файл (root-ca.conf), в котором мы укажем OpenSSL, что же именно хотим получить в итоге. Большую часть времени (при повседневном использовании OpenSSL) подобные файлы конфигурации не требуются, однако для выполнения сложных операций, таких как создание корневого УЦ, они необходимы. Конфигурационные файлы OpenSSL весьма мощные; прежде чем продолжать, есть смысл ознакомиться с их возможностями (выполните man config в командной строке).

Первая часть конфигурационного файла содержит основную информацию об УЦ, такую как имя и базовый URL, а также компоненты отличительного имени УЦ. Из-за гибкости синтаксиса, эту информацию нужно предоставить лишь один раз:

[default]
name                    = root-ca
domain_suffix           = example.com
aia_url                 = http://$name.$domain_suffix/$name.crt
crl_url                 = http://$name.$domain_suffix/$name.crl
ocsp_url                = http://ocsp.$name.$domain_suffix:9080
default_ca              = ca_default
name_opt                = utf8,esc_ctrl,multiline,lname,align

[ca_dn]
countryName             = "GB"
organizationName        = "Example"
commonName              = "Root CA"

Вторая часть файла напрямую контролирует работу УЦ. Для получения полной информации о каждом параметре обратитесь к документации по команде ca (выполните man ca в командной строке). Большинство настроек говорят сами за себя; в основном мы сообщаем OpenSSL, где хотим хранить наши файлы. Поскольку этот корневой УЦ будет использоваться только для выпуска ключей и сертификатов подчиненных УЦ, я решил, что его сертификат будет действителен в течение 10 лет. Для формирования электронной подписи по умолчанию будет использован безопасный алгоритм хэширования SHA256.

Политика по умолчанию (policy_c_o_match) сконфигурирована таким образом, что все сертификаты, издаваемые данным УЦ, будут иметь те же значения в полях countryName и organizationName, что и в сертификате самого УЦ. Обычно в публичных УЦ так не делается, но для частного УЦ это вполне приемлемый вариант:

[ca_default]
home                    = .
database                = $home/db/index
serial                  = $home/db/serial
crlnumber               = $home/db/crlnumber
certificate             = $home/$name.crt
private_key             = $home/private/$name.key
RANDFILE                = $home/private/random
new_certs_dir           = $home/certs
unique_subject          = no
copy_extensions         = none
default_days            = 3650
default_crl_days        = 365
default_md              = sha256
policy                  = policy_c_o_match

[policy_c_o_match]
countryName             = match
stateOrProvinceName     = optional
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

Третья часть файла содержит конфигурацию для команды req, которая будет использоваться только один раз при создании самоподписанного корневого сертификата. Самой важной частью здесь являются расширения: значение в basicConstraints указывает на то, что это сертификат УЦ, а в keyUsage содержатся настройки, соответствующие этому сценарию:

[req]
default_bits            = 4096
encrypt_key             = yes
default_md              = sha256
utf8                    = yes
string_mask             = utf8only
prompt                  = no
distinguished_name      = ca_dn
req_extensions          = ca_ext

[ca_ext]
basicConstraints        = critical,CA:true
keyUsage                = critical,keyCertSign,cRLSign
subjectKeyIdentifier    = hash

В четвёртой части конфигурационного файла содержится информация, которая будет использоваться при создании сертификатов, издаваемых корневым удостоверяющим центром. Все эти сертификаты будут сертификатами УЦ (на что указывает содержимое расширения basicConstraints), но мы также задаём pathlen в ноль, а это означает, что создание дальнейших подчинённых УЦ (более глубокой вложенности) не допускается.

Все наши подчинённые УЦ будут ограничены в том смысле, что выданные ими сертификаты будут действительны только для определённых подмножеств доменных имён и только для ограниченного использования. Во-первых, в расширении extendedKeyUsage заданы только значения clientAuth и serverAuth, то есть ключи могут быть использованы только для аутентификации клиента и сервера TLS. Во-вторых, расширение nameConstraints ограничивает разрешённые имена хостов только значениями в пределах доменных имён example.com и example.org. В теории, такая настройка позволяет вам передать управление подчинёнными УЦ кому-то ещё, но при этом оставаться уверенным, что они не смогут выдавать сертификаты для произвольных имён хостов. При желании можно ограничить каждый подчинённый УЦ своим строго определённым (возможно, небольшим) пространством доменных имён. Требование об исключении двух диапазонов IP-адресов продиктовано «Базовыми требованиями» CA/Browser Forum14, в которых имеется определение технически ограниченного подчинённого УЦ.

На практике, установление ограничений на имена хостов работает не в полной мере, поскольку в настоящее время некоторые крупные платформы не распознают расширение nameConstraints. Если вы пометите это расширение как критичное, такие платформы будут отклонять ваши сертификаты. Этих проблем не возникнет, если вы не станете помечать расширение как критичное (как в нашем примере), но тогда некоторые другие платформы не будут его применять.

[sub_ca_ext]
authorityInfoAccess     = @issuer_info
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:true,pathlen:0
crlDistributionPoints   = @crl_info
extendedKeyUsage        = clientAuth,serverAuth
keyUsage                = critical,keyCertSign,cRLSign
nameConstraints         = @name_constraints
subjectKeyIdentifier    = hash

[crl_info]
URI.0                   = $crl_url

[issuer_info]
caIssuers;URI.0         = $aia_url
OCSP;URI.0              = $ocsp_url

[name_constraints]
permitted;DNS.0=example.com
permitted;DNS.1=example.org
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0

В финальной пятой части нашего файла указываются расширения, которые будут использоваться с сертификатом для подписи ответов OCSP. Чтобы иметь возможность запустить ответчик OCSP, мы генерируем специальный ключ (и сертификат) и делегируем ему возможность подписи OCSP. Как можно установить из расширений, этот сертификат не будет сертификатом УЦ:

[ocsp_ext]
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:false
extendedKeyUsage        = OCSPSigning
keyUsage                = critical,digitalSignature
subjectKeyIdentifier    = hash

Структура каталогов корневого УЦ

На следующем шаге мы создаём определённую в предыдущем разделе структуру каталогов и инициализируем некоторые файлы, которые будут использованы при выполнении операций УЦ:

$ mkdir root-ca
$ cd root-ca
$ mkdir certs db private
$ chmod 700 private
$ touch db/index
$ openssl rand -hex 16  > db/serial
$ echo 1001 > db/crlnumber

Будут использоваться следующие поддиректории:

certs/

Хранилище сертификатов; новые сертификаты будут размещаться здесь по мере их выдачи.

db/

В данной директории находится база данных сертификатов (index), а также файлы, в которых хранятся серийные номера следующих сертификата и CRL. По мере необходимости OpenSSL будет создавать здесь дополнительные файлы.

private/

В этой директории будут храниться закрытые ключи, один для корневого УЦ и ещё один для ответчика OCSP. Важно, чтобы у других пользователей не было доступа к этой директории. На самом деле, если вы собираетесь серьёзно относиться к этому УЦ, на машине, где хранятся корневые материалы, должно быть минимально возможное количество учётных записей пользователей.

Примечание: При создании нового сертификата удостоверяющего центра важно инициализировать серийные номера сертификатов с помощью генератора случайных чисел, как сделано у меня в этом разделе. Это очень полезно, если вам когда-нибудь придётся создавать и развёртывать несколько сертификатов УЦ с одинаковым отличительным именем (обычно такое случается, если вы допустили ошибку и вынуждены начинать всё заново); конфликтов не будет, потому что сертификаты будут иметь разные серийные номера.

Генерация корневого УЦ

Мы разобьём создание корневого УЦ на два этапа. На первом мы сгенерируем ключ и CSR. Вся необходимая информация будет взята из конфигурационного файла, который мы зададим в параметре -config:

$ openssl req -new 
    -config root-ca.conf 
    -out root-ca.csr 
    -keyout private/root-ca.key

На втором этапе мы создадим самоподписанный сертификат. Параметр -extensions указывает на раздел ca_ext конфигурационного файла, активирующий расширения, предназначенные для корневого удостоверяющего центра:

$ openssl ca -selfsign 
    -config root-ca.conf 
    -in root-ca.csr 
    -out root-ca.crt 
    -extensions ca_ext

Структура файла базы данных

База данных в файле db/index представляет собой обычный текстовый файл, содержащий информацию о сертификатах, по одному сертификату в каждой строке. Сразу после создания корневого УЦ в нём будет содержаться одна строка:

V    240706115345Z        1001    unknown    /C=GB/O=Example/CN=Root CA

В каждой строке шесть значений, разделённых знаками табуляции:

  1. Флаг статуса (V для валидного сертификата, R для отозванного, E сертификата с истёкшим сроком действия).

  2. Дата окончания срока действия (в формате YYMMDDHHMMSSZ).

  3. Дата отзыва, либо пустое поле, если сертификат не отозван.

  4. Серийный номер (в шестнадцатеричном формате).

  5. Расположение файла или unknown, если оно неизвестно.

  6. Уникальное (отличительное) имя.

Операции, выполняемые в рамках корневого УЦ

Для генерации CRL в новом УЦ используйте параметр -gencrl команды ca:

$ openssl ca -gencrl 
    -config root-ca.conf 
    -out root-ca.crl

Для выпуска сертификата выполняйте команду ca с нужными параметрами. Важно, чтобы параметр -extensions указывал на требуемый раздел конфигурационного файла (вы же не собираетесь создать ещё один корневой удостоверяющий центр).

$ openssl ca 
    -config root-ca.conf 
    -in sub-ca.csr 
    -out sub-ca.crt 
    -extensions sub_ca_ext

Для отзыва сертификата используйте параметр -revoke команды ca; вам необходимо иметь копию сертификата, который вы хотите отозвать. Поскольку все сертификаты хранятся в директории certs/, вам нужно знать только его серийный номер. Если вы знаете уникальное имя субъекта сертификата, можно найти серийный номер в базе данных.

Выберите корректную причину отзыва и укажите её в параметре -crl_reason. Возможные варианты: unspecified, keyCompromise, CACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold и removeFromCRL.

$ openssl ca 
    -config root-ca.conf 
    -revoke certs/1002.pem 
    -crl_reason keyCompromise

Создание сертификата для подписи ответов OCSP

Сначала надо создать ключ и CSR для ответчика OCSP. Поскольку ключ и будущий сертификат не будут ключом и сертификатом удостоверяющего центра, при выполнении этой оперции мы не будем ссылаться на наш конфигурационный файл:

$ openssl req -new 
    -newkey rsa:2048 
    -subj "/C=GB/O=Example/CN=OCSP Root Responder" 
    -keyout private/root-ocsp.key 
    -out root-ocsp.csr

Затем мы выпустим сертификат ответчика OCSP, используя наш корневой УЦ. В качестве значения параметра -extensions мы укажем ocsp_ext, в этом разделе конфигурационного файла заданы расширения, относящиеся к подписанию ответов OCSP. Я сократил срок действия нового сертификата до 365 дней (вместо установленных по умолчанию 3650 дней). Поскольку в подобных сертификатах OCSP не содержится информация об отзыве, они не могут быть отозваны. По этой причине целесообразно установить срок действия такого сертификата настолько коротким, насколько это возможно. Хорошим выбором будет 30 дней, при условии, что вы готовы создавать новые сертификаты с такой частотой:

$ openssl ca 
    -config root-ca.conf 
    -in root-ocsp.csr 
    -out root-ocsp.crt 
    -extensions ocsp_ext 
    -days 30

Теперь мы полностью готовы к запуску ответчика OCSP. Для тестирования можно сделать это с той же машины, на которой размещается корневой УЦ, но в реальной производственной среде необходимо переместить ключ и сертификат ответчика OCSP в другое место.

$ openssl ocsp 
    -port 9080
    -index db/index 
    -rsigner root-ocsp.crt 
    -rkey private/root-ocsp.key 
    -CA root-ca.crt 
    -text

Работу ответчика OCSP можно протестировать следующей командой:

$ openssl ocsp 
    -issuer root-ca.crt 
    -CAfile root-ca.crt 
    -cert root-ocsp.crt 
    -url http://127.0.0.1:9080

В выводе команды verify OK означает, что проверка подписей прошла успешно, а good — что сертификат не был отозван.

Response verify OK
root-ocsp.crt: good
        This Update: Jul  9 18:45:34 2014 GMT

Создание подчинённого УЦ

Процесс создания подчиненного УЦ во многом аналогичен тому, который мы выполняли для корневого УЦ. В этом разделе мы главным образом будем останавливаться на их различиях, всё остальное можно найти в предыдущем разделе.

Конфигурация подчинённого УЦ

Чтобы составить конфигурационный файл для подчинённого УЦ (sub-ca.conf), возьмём за основу файл, который мы использовали для корневого УЦ, и внесём в него перечисленные ниже изменения. Мы изменим имя на sub-ca и будем использовать другое отличительное имя. Ответчик OCSP будет принимать запросы на другом порту, но лишь потому, что команда ocsp не умеет работать с виртуальными хостами. Если для организации ответчика OCSP используется полноценный веб-сервер, можно вообще обойтись без специализированных портов. По умолчанию срок действия новых сертификатов составит 365 дней, свежий CRL мы будем генерировать каждые 30 дней.

Изменение параметра copy_extensions на значение copy означает, что указанные в CSR расширения будут скопированы в сертификат, но только в том случае, если аналогичные расширения не были заданы в нашей конфигурации. При такой настройке те, кто готовят CSR, могут поместить в него необходимые альтернативные имена, и информация о них будет собрана и помещена в сертификат. Эта функция может быть потенциально опасна (вы позволяете стороннему лицу иметь ограниченный прямой контроль над тем, что попадёт в сертификат), но в небольших окружениях это вполне приемлемо:

[default]
name                    = sub-ca
ocsp_url                = http://ocsp.$name.$domain_suffix:9081

[ca_dn]
countryName             = "GB"
organizationName        = "Example"
commonName              = "Sub CA"

[ca_default]
default_days            = 365
default_crl_days        = 30
copy_extensions         = copy

В конце конфигурационного файла добавим два новых профиля: для клиента и для сервера. Различия между ними будут только в расширениях keyUsage и extendedKeyUsage. Обратите внимание, что мы указали расширение basicConstraints, но задали его в false. Это сделано потому, что мы копируем расширения из CSR. Если бы мы пропустили данное расширение, то вполне могли бы получить его из CSR с тем значением, которое указано там:

[server_ext]
authorityInfoAccess     = @issuer_info
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:false
crlDistributionPoints   = @crl_info
extendedKeyUsage        = clientAuth,serverAuth
keyUsage                = critical,digitalSignature,keyEncipherment
subjectKeyIdentifier    = hash

[client_ext]
authorityInfoAccess     = @issuer_info
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:false
crlDistributionPoints   = @crl_info
extendedKeyUsage        = clientAuth
keyUsage                = critical,digitalSignature
subjectKeyIdentifier    = hash

После того, как вы доведёте до ума конфигурационный файл, создайте структуру каталогов, следуя тем же инструкциям, что и для корневого УЦ, только не забудьте указать другое имя директории, например, sub-ca.

Генерация подчинённого УЦ

Как и в прошлый раз, создание подчинённого УЦ будем выполнять в два этапа. На первом сгенерируем ключ и CSR. Всю необходимую информацию получим из конфигурационного файла, используя параметр -config.

$ openssl req -new 
    -config sub-ca.conf 
    -out sub-ca.csr 
    -keyout private/sub-ca.key

На втором этапе мы воспользуемся корневым УЦ для выпуска сертификата. Параметр -extensions указывает на раздел конфигурационного файла sub_ca_ext, в котором активируются расширения, соответствующие подчинённому УЦ.

$ openssl ca 
    -config root-ca.conf 
    -in sub-ca.csr 
    -out sub-ca.crt 
    -extensions sub_ca_ext

Операции, выполняемые в рамках подчинённого УЦ

Для выпуска сертификата сервера при обработке CSR в параметре -extensions указывается server_ext:

$ openssl ca 
    -config sub-ca.conf 
    -in server.csr 
    -out server.crt 
    -extensions server_ext

Для выпуска сертификата клиента при обработке CSR в параметре -extensions указывается client_ext:

$ openssl ca 
    -config sub-ca.conf 
    -in client.csr 
    -out client.crt 
    -extensions client_ext

Примечание: При поступлении нового запроса на подписание сертификата, вся содержащаяся в нём информация должна быть представлена вам для проверки перед выполнением операции выпуска сертификата. Всегда следует проверить информацию и убедиться в том, что всё в порядке, но особенно в том случае, если CSR был подготовлен сторонним лицом. Обращайте особое внимание на отличительное имя сертификата, а также расширения basicConstraints и subjectAlternativeName.

Генерация CRL и отзыв сертификата осуществляются также, как и для корневого УЦ. Отличается лишь порт ответчика OCSP, для подчинённого УЦ это будет 9081. Рекомендуется, чтобы ответчик использовал свой собственный сертификат, что позволит избежать хранения подчинённого УЦ на общедоступном сервере.

Примечания

[1] Буквы “eay” в названии SSLeay представляют собой инициалы разработчика Eric A. Young.

[2] BoringSSL (Chromium, проверено 30 июня 2015 г.)

[3] Win32 OpenSSL (Shining Light Productions, проверено 3 июля 2014 г.)

[4] Бинарники и модули Apache 2.4 VC14 (Apache Lounge, проверено 15 июля 2015 г.)

[5] Пакет исходных кодов “openssl” в Precise (Ubuntu, проверено 3 июля 2014 г.)

[6] Компиляция с усиленной защитой в Ubuntu и Debian (Kees Cook, 3 февраля 2014 г.)

[7] Существуют организации, в которых придерживаются очень строгих требований обеспечения безопасности, в частности, защита закрытых ключей в них должна быть обеспечена любой ценой. Решением для таких организаций может стать инвестирование в Аппаратные модули безопасности (Hardware Security Module, HSM) — продукты, специально разработанные для того, чтобы сделать извлечение ключей невозможным даже при физическом доступе к серверу. Для достижения этого HSM не только генерируют и хранят ключи, но также выполняют все необходимые операции (например, генерацию электронной подписи). Обычно HSM очень дороги.

[8] RFC 2985: PKCS #9: Избранные объектные классы и типы атрибутов, версия 2.0 (M. Nystrom и B. Kaliski, ноябрь 2000 г.)

[9] Криптография/Атака «встреча посередине» (Wikibooks, проверено 31 марта 2014 г.)

[10] Публикация «Attacking Triple Encryption» («Техники атак на 3DES») (Stefan Lucks, 1998 г.)

[11] Публикация «On the Security of RC4 in TLS and WPA» («О безопасности RC4 в TLS и WPA») (AlFardan и другие, 13 марта 2013 г.)

[12] RFC 7905: Наборы алгоритмов шифрования для TLS ChaCha20-Poly1305 (Langley и другие, июнь 2016 г.)

[13] Шаблоны конфигурации УЦ для OpenSSL (GitHub-репозиторий книги «Bulletproof SSL and TLS», проверено 31 марта 2017 г.)

[14] «Базовые требования» (The CA/Browser Forum, проверено 9 июля 2014 г.)

Copyright © 2020 Feisty Duck. Все права защищены.

Переведено участниками проекта Pro-LDAP.ru в 2020 году.

Contents

  1. Introduction
  2. Target Audience
  3. About OpenSSL

    1. About X.509
  4. Practical OpenSSL Usage

    1. Basic OpenSSL Commands
  5. SSL Certificates

    1. SSL Certificates for Server Use
    2. Using PKCS#12 Certificates in Client Applications
  6. Configuring Apache for SSL Support
  7. Resources

    1. Local System Resources
    2. WWW Resources

Introduction

This guide is designed to introduce the reader to the Secure Sockets Layer (SSL) application-level protocol, and particularly the OpenSSL implementation of SSL. After a brief description of exactly what OpenSSL is, and what it is useful for, the guide will further illustrate the practical usage of OpenSSL in a client-server environment, and provide specific examples of applications which may benefit from OpenSSL. Finally, the guide will lead the user through example procedures required to use OpenSSL with the popular Apache Hyper Text Transport Protocol (HTTP) server for the purpose of serving secured web pages from your Ubuntu computer.

Target Audience

To properly implement the practical steps found in this guide, the reader should be a user of Ubuntu who is comfortable with the use of command-line applications, using the Bourne Again SHell (bash) environment, and editing system configuration files with their preferred text editor application. While previous familiarity with Server Sockets Layer (SSL), or the OpenSSL implementation in particular, is not required for this guide, if desired, the reader is advised to pursue further learning from the resources listed in the Resources section of this guide in order to broaden his/her understanding of this powerful security layer.

About OpenSSL

Secure Sockets Layer is an application-level protocol which was developed by the Netscape Corporation for the purpose of transmitting sensitive information, such as Credit Card details, via the Internet. SSL works by using a private key to encrypt data transferred over the SSL-enabled connection, thus thwarting eavesdropping of the information. The most popular use of SSL is in conjunction with web browsing (using the HTTP protocol), but many network applications can benefit from using SSL. By convention, URLs that require an SSL connection start with https: instead of http:.

OpenSSL is a robust, commercial-grade implementation of SSL tools, and related general purpose library based upon SSLeay, developed by Eric A. Young and Tim J. Hudson. OpenSSL is available as an Open Source equivalent to commercial implementations of SSL via an Apache-style license.

About X.509

X.509 is a specification for digital certificates published by the International Telecommunications Union — Telecommunication (ITU-T). It specifies information and attributes required for the identification of a person or a computer system, and is used for secure management and distribution of digitally signed certificates across secure Internet networks. OpenSSL most commonly uses X.509 certificates.

Practical OpenSSL Usage

Installing OpenSSL Toolkit

To install the OpenSSL binary toolkit, install the following packages openssl (see InstallingSoftware).

Installing OpenSSL Library

To install the OpenSSL general-purpose library, first determine the applicable version of the library available for your Ubuntu computer with the following command issued at a terminal prompt:

apt-cache search libssl | grep SSL

You should observe output from the command similar to the following:

libssl0.9.6 - SSL shared libraries (old version)
libssl-dev - SSL development libraries, header files and documentation
libssl0.9.7 - SSL shared libraries

In the above example, you would most likely want to install the current OpenSSL library, which appears in the output as libssl0.9.7 (like sudo apt-get install libssl0.9.7. Install the following packages libssl0.9.7 (see InstallingSoftware). You may also need to install ca-certificates.

Installing OpenSSL Development Library

In order to build software which requires the OpenSSL general-purpose library, you must first install the development instance of the OpenSSL library. Install the following packages libssl-dev (see InstallingSoftware). Due to OpenSSL’s license being incompatible with the GPL, linking the OpenSSL library with programs covered by GPL requires an explicit linking exception for packages present in the Ubuntu Archive. (Ubuntu Technical Board decision)

Basic OpenSSL Commands

The following section of the guide presents some of the more common basic commands, and parameters to commands which are part of the OpenSSL toolkit. For additional information, read the various OpenSSL system manual pages with the man command, and refer to the information presented in the Resources section of this guide.

Determine installed OpenSSL version:

openssl version

List of available OpenSSL sub-commands:

openssl help

Get additional help information on OpenSSL sub-commands by using the openssl command followed by the sub-command, and the -h switch. For example, to get additional information on the openssl enc sub-command:

openssl -h enc

List all available cipher algorithms:

openssl ciphers -v

You may benchmark your computer’s speed with OpenSSL, measuring how many bytes per second can be processed for each algorithm, and the times needed for sign/verify cycles by using the following command:

openssl speed

SSL Certificates

The following sections of this guide will introduce the concepts involved in the generation and use of SSL certificates, both the self-signed variety, and those signed by a recognized certificate authority for use with a server application supporting SSL, and the use of X.509 certificates in client applications.

SSL Certificates for Server Use

Once you have properly generated an X.509-compliant SSL certificate, you may either elect to sign the certificate yourself, by generating a Certificate Authority (CA), or you may opt to have a globally recognized Certificate Authority sign the certificate. When the certificate is signed, it is then ready to be used with the OpenSSL toolkit, or the library to enable encrypted SSL connections to a Lightweight Directory Access Protocol, (LDAP) or Hyper Text Transport Protocol (HTTP) server, for example. This section of the guide describes the certificate generation, and signing process for both self-signed, and recognized CA-signed certificates.

Generating and Signing Self-Signed Certificates

Self-signed certificates have a major advantage in that they are completely free to use, and they may be generated, signed, and used on an as-needed basis. Self-signed certificates are great for use in closed-lab environments or for testing purposes. One of the drawbacks of using self-signed certificates, however, is that warnings will typically be issued by a user’s Web browser, and other applications, upon accessing an SSL-secured server that uses a self-signed certificate. By default, client applications (e.g., Firefox) will suppress such warnings for certificates that are signed using only a globally-recognized and trusted Certificate Authority, but warnings may also be squelched by importing a server’s root certificate into client applications; a relevant demonstration is shown later in this guide. Using self-signed certificates in a publicly-accessible, production environment is not recommended due to the implicit trust issues arising from these warnings, in addition to the potential confusion caused to users.

IconsPage/note.png NOTE: You must obtain a certificate signed by a recognized Certificate Authority in order to establish a commercial site, e.g., for conducting «e-commerce».

Provided you’ve installed the OpenSSL toolkit previously, or per instructions above, the generation of X.509 SSL certificates is quite simple. For self-signed certificates, you must first establish a Certificate Authority (CA) by following the steps below:

First, create an initial working environment, for example within your home directory by issuing the following command from a terminal prompt:

cd && mkdir -p myCA/signedcerts && mkdir myCA/private && cd myCA

The above command will place you in a newly-created subdirectory of your home directory named myCA, and within this subdirectory, you should have two additional subdirectories named signedcerts and private.

Within this initial working environment, the significance of the subdirectories, and their contents is as follows:

  • ~/myCA : contains CA certificate, certificates database, generated certificates, keys, and requests

  • ~/myCA/signedcerts : contains copies of each signed certificate

  • ~/myCA/private : contains the private key

Next, create an initial certificate database in the ~/myCA subdirectory with the following command at a terminal prompt:

echo ’01’ > serial  && touch index.txt

Now create an initial caconfig.cnf file suitable for the creation of CA certificates. Using your favorite editor, edit the file ~/myCA/caconfig.cnf, and insert the following content into the file:

sudo nano ~/myCA/caconfig.cnf
# My sample caconfig.cnf file.
#
# Default configuration to use when one is not provided on the command line.
#
[ ca ]
default_ca      = local_ca
#
#
# Default location of directories and files needed to generate certificates.
#
[ local_ca ]
dir             = /home/<username>/myCA
certificate     = $dir/cacert.pem
database        = $dir/index.txt
new_certs_dir   = $dir/signedcerts
private_key     = $dir/private/cakey.pem
serial          = $dir/serial
#       
#
# Default expiration and encryption policies for certificates.
#
default_crl_days        = 365
default_days            = 1825
default_md              = sha1
#       
policy          = local_ca_policy
x509_extensions = local_ca_extensions
#
#
# Copy extensions specified in the certificate request
#
copy_extensions = copy
#       
#
# Default policy to use when generating server certificates.  The following
# fields must be defined in the server certificate.
#
[ local_ca_policy ]
commonName              = supplied
stateOrProvinceName     = supplied
countryName             = supplied
emailAddress            = supplied
organizationName        = supplied
organizationalUnitName  = supplied
#       
#
# x509 extensions to use when generating server certificates.
#
[ local_ca_extensions ]
basicConstraints        = CA:false
#       
#
# The default root certificate generation policy.
#
[ req ]
default_bits    = 2048
default_keyfile = /home/<username>/myCA/private/cakey.pem
default_md      = sha1
#       
prompt                  = no
distinguished_name      = root_ca_distinguished_name
x509_extensions         = root_ca_extensions
#
#
# Root Certificate Authority distinguished name.  Change these fields to match
# your local environment!
#
[ root_ca_distinguished_name ]
commonName              = MyOwn Root Certificate Authority
stateOrProvinceName     = NC
countryName             = US
emailAddress            = root@tradeshowhell.com
organizationName        = Trade Show Hell
organizationalUnitName  = IT Department
#       
[ root_ca_extensions ]
basicConstraints        = CA:true

IconsPage/warning.png IMPORTANT: Make sure to adjust the obvious site-specific details in the file, such as the two instances of /home/<username>/ under [ local_ca ] and [ req ]. Also change commonName, stateOrProvinceName countryName etc under [ root_ca_distinguished_name ] to personalize for your environment. For more information on the directives contained within this configuration file, use the man config command.

When you’ve edited the file to match your environment, save the file as ~/myCA/caconfig.cnf.

Next, you need to generate the Certificate Authority Root Certificate and Key, by issuing a few commands. First, do this:

export OPENSSL_CONF=~/myCA/caconfig.cnf

The previous command sets an environment variable, OPENSSL_CONF, which forces the openssl tool to look for a configuration file in an alternative location (in this case, ~/myCA/caconfig.cnf).

Now, generate the CA certificate and key with the following command:

openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM -days 1825

You should be prompted for a passphrase, and see output similar to this:

Generating a 2048 bit RSA private key
.................................+++
.................................................................................................+++
writing new private key to '/home/bshumate/myCA/private/cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----

Do not forget the passphrase used with the command above! You’ll need it every time you want to generate and sign a new server or client certificate!

The above process will create a self-signed certificate using PEM format and RSA public/private key encryption. The certificate will be valid for 1825 days. The location, and purpose of the resultant files is as follows:

  • ~/myCA/cacert.pem : CA public certificate

  • ~/myCA/private/cakey.pem : CA private key

Optional Step

Strip the certificate from all its text to keep only the -CERTIFICATE- section to create a crt

openssl x509 -in cacert.pem -out cacert.crt
Creating a Self-Signed Server Certificate

Now that you have a Certificate Authority configured, you may use it to sign self-signed certificates. Prior to beginning the steps below, you may wish to encrypt the certificate’s private key with a passphrase. The advantages of encrypting the key with a passphrase include protection of the certificate in the event it is stolen.

The certificate cannot be used with SSL-enabled applications without entering the passphrase every time the SSL-enabled application is started. This condition, while being most secure, can present a problem: If the server must be started in an unattended manner as in the case of a computer restart, then no one will be available to enter the passphrase, and subsequently the server will not start. One way to eliminate this condition involves a trade-off in security: The key may be decrypted, to remove the passphrase necessity; thus SSL-enabled applications will start automatically, without a need for you to enter a passphrase.

To actually generate a self-signed certificate for use with an SSL application, follow this process:

Create the server configuration file, by editing ~/myCA/exampleserver.cnf with your favorite text editor. Add this example content:

#
# exampleserver.cnf
#

[ req ]
prompt                  = no
distinguished_name      = server_distinguished_name
req_extensions          = v3_req

[ server_distinguished_name ]
commonName              = tradeshowhell.com
stateOrProvinceName     = NC
countryName             = US
emailAddress            = root@tradeshowhell.com
organizationName        = My Organization Name
organizationalUnitName  = Subunit of My Large Organization

[ v3_req ]
basicConstraints        = CA:FALSE
keyUsage                = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName          = @alt_names

[ alt_names ]
DNS.0                   = tradeshowhell.com
DNS.1                   = alt.tradeshowhell.com

Be sure to change the values under server_distinguished_name especially the commonName value. The commonName value must match the host name, or CNAME for the host you wish to use the key for. If the commonName does not match the intended hostname, then host / certificate mismatch errors will appear in the client applications of clients attempting to access the server.

Once you’ve edited the file appropriately, save it as ~/myCA/exampleserver.cnf. Generate the server certificate, and key with the following commands:

export OPENSSL_CONF=~/myCA/exampleserver.cnf

The previous command sets an environment variable OPENSSL_CONF which forces the openssl tool to look for a configuration file in an alternative location (in this case, ~/myCA/exampleserver.cnf).

Now generate the certificate, and key:

openssl req -newkey rsa:1024 -keyout tempkey.pem -keyform PEM -out tempreq.pem -outform PEM

You should be prompted for a passphrase, and see output similar to this:

Generating a 1024 bit RSA private key
...++++++
...............++++++
writing new private key to 'tempkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----

Don’t forget the passphrase!

Next, you may translate the temporary private key into an unencrypted key by using the following command:

openssl rsa < tempkey.pem > server_key.pem

You should be prompted for the passphrase used above, and see the following output:

Enter pass phrase:
writing RSA key

If you wish to leave the key encrypted with a passphrase, simply rename the temporary key using the following command, instead of following the step above:

mv tempkey.pem server_key.pem

IconsPage/tip.png Remember: If you use a server key encrypted with a passphrase, the passphrase will have to be entered each time the server application using the encrypted key is started. This means the server application will not start unless someone, or something enters the key.

Now you need to sign the server certificate with the Certificate Authority (CA) key using these commands:

export OPENSSL_CONF=~/myCA/caconfig.cnf

The previous command modifies the environment variable OPENSSL_CONF which forces the openssl tool to look for a configuration file in an alternative location (in this case, ~/myCA/caconfig.cnf to switch back to the CA configuration).

Then sign the certificate as follows:

openssl ca -in tempreq.pem -out server_crt.pem

You will be prompted for the passphrase of the CA key as created in the Certificate Authority setup from above. Enter this passphrase at the prompt, and you will then be prompted to confirm the information in the exampleserver.cnf, and finally asked to confirm signing the certificate. Output should be similar to this:

Using configuration from /home/bshumate/myCA/caconfig.cnf
Enter pass phrase for /home/bshumate/myCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :PRINTABLE:'tradeshowhell.com'
stateOrProvinceName   :PRINTABLE:'NC'
countryName           :PRINTABLE:'US'
emailAddress          :IA5STRING:'root@tradeshowhell.com'
organizationName      :PRINTABLE:'Trade Show Hell'
organizationalUnitName:PRINTABLE:'Black Ops'
Certificate is to be certified until Jan  4 21:50:08 2011 GMT (1825 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Remove the temporary certificate, and key files with the following command:

rm -f tempkey.pem && rm -f tempreq.pem

Congratulations! You now have a self-signed server application certificate, and key pair:

  • server_crt.pem : Server application certificate file

  • server_key.pem : Server application key file

Use the documentation provided with the server application you wish to use the certificate, and key for in order to properly use it. See the Configuring Apache for SSL Support section below for an example usage.

Optional Step for Certain Server Applications

Some server applications, such as the Courier IMAP mail server application require that the unencrypted private key be prepended to the server certificate. To accomplish this, simply enter the following commands:

cat server_key.pem server_crt.pem > hold.pem
mv      hold.pem server_crt.pem
chmod   400      server_crt.pem
Converting X.509 Certificates to PKCS#12 for Client Applications

If you wish to generate PKCS#12 certificates from your server’s Root CA X.509 certificate for client use, you will need to use the following process on the particular server certificate, and key pair you desire to export a client certificate for:

Create a single file containing both the certificate, and key with the following command:

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem

Then, convert this certificate / key combination file into the PKCS#12 certificate with the following command:

openssl pkcs12 -export -out mycert.pfx -in mycert.pem -name «Certificate for Whatever»

You will be prompted for an Export password, which you may use, or just leave blank.

The resultant mycert.pfx file may now be imported into applications such as Web Browsers, and E-Mail clients. Since this certificate represents the Root CA certificate of your server, all subsequent server-level certificates signed by the CA certificate will also be automatically accepted by the client application which installs this PKCS#12 version of the certificate.

Generating Certificate for Signing by Recognized CA

In order to run a production server which will engage in commercial activity, such as «e-commerce», it is required to generate a certificate, and have it signed by a recognized Certificate Authority (CA) such as VeriSign. The process for generating a certificate request, and obtaining a certificate signed by a recognized CA can be difficult. You must complete all requisite «paperwork» prior to creating a certificate request, and ensure all required information is accurate.

Assuming you do not wish a passphrase-encrypted key, enter the following command to generate the private key, and certificate request:

openssl req -new -newkey rsa:1024 -nodes -keyout mykey.pem -out myreq.pem

If you already have a key you wish to use, then use the following command instead:

openssl req -new -key mykey.pem -out myreq.pem

You may wish to verify the signature, and information contained in the certificate request. Verify the signature with this command:

openssl req -in myreq.pem -noout -verify -key mykey.pem

and verify the information with this command:

openssl req -in myreq.pem -noout -text

The next steps typically involve pasting the content of the certificate request file into the CA’s signup form, and awaiting the certificate. Also, you should safeguard the key file, as it will be required to use the certificate you receive from the CA.

Using PKCS#12 Certificates in Client Applications

This section of the guide explains using PKCS#12 certificates for SSL connections from the client perspective, and demonstrates the process of importing certificates into the Firefox Web Browser applications, and a couple of the more popular E-Mail clients.

Importation of a root certificate into such applications enables a trusted SSL-encrypted connection to the server from whence the certificate came, free of nagging messages about the certificate being self-signed, and so on.

Importing a Certificate into Mozilla Firefox

Importation of a PKCS#12 certificate into the Mozilla Firefox Web Browser application is very simple:

  1. From within Firefox, click Edit > Preferences

  2. Click the Advanced icon

  3. Click the View Certificates button

  4. Click the Import button

  5. Browse to the location of the certificate file, which is typically a .pfx file type

  6. Highlight the certificate file, and click the Open button

  7. You may be prompted to enter Firefox’s Master Password at this point, or to set an initial Master Password. Enter the current, or net password as required, confirm it, and click OK

  8. You will then be prompted to enter the certificate’s Export password. If there is no such password attached to the certificate, simply click OK, otherwise enter the password, and click OK

  9. A message will appear advising that Firefox has «Successfully restored your security certificate(s) and private key(s)»
  10. Click OK

  11. You have successfully imported the server’s client PKCS#12 certificate into Firefox

Importing a Certificate into Evolution

Importation of a PKCS#12 certificate into the Evolution E-Mail client couldn’t be simpler:

  1. From within Evolution, click Edit > Preferences

  2. Click the Certificates icon

  3. Click the Import button

  4. Browse to the location of the certificate file, which is typically a .pfx file type

  5. Highlight the certificate file, and click the Open button

  6. You may be prompted to enter Evolution’s certificate database password at this point, or to set an initial certificate database password. Enter the current, or new password as required, confirm it, and click OK

  7. You will then be prompted to enter the PKCS12 File Password. If there is no such password attached to the certificate, simply click OK, otherwise enter the password, and click OK

  8. You should see the certificate, and its details appear in the Your Certificates section of the Evolution Settings window

  9. Click the Close button

  10. You have successfully imported the server’s client PKCS#12 certificate into Evolution

Importing a Certificate into Mozilla Thunderbird

Importation of a PKCS#12 certificate into the Mozilla Thunderbird E-Mail client application is very simple:

  1. From within Thunderbird, click Edit > Preferences

  2. Click the Advanced icon

  3. Click the Certificates entry in the right pane

  4. Click the Manage Certificates button

  5. Click the Import button

  6. Browse to the location of the certificate file, which is typically a .pfx file type

  7. Highlight the certificate file, and click the Open button

  8. You may be prompted to enter Thunderbird’s Master Password at this point, or to set an initial Master Password. Enter the current, or new password as required, confirm it, and click OK

  9. You will then be prompted to enter the certificate’s Export password. If there is no such password attached to the certificate, simply click OK, otherwise enter the password, and click OK

  10. A message will appear advising that Thunderbird has «Successfully restored your security certificate(s) and private key(s)»
  11. Click OK

  12. You have successfully imported the server’s client PKCS#12 certificate into Thunderbird

Importing a Certificate into the System-Wide Certificate Authority Database

You can import a CA Certificate into the system-wide database of trusted certificate authorities. Applications that use this database will automatically trust any certificates stored here.

1. Copy your certificate to the system certificate directory. At a terminal prompt, type:

$ sudo cp mycert.pem /usr/share/ca-certificates/mycert.crt

2. Edit the ca-certificates configuration file /etc/ca-certificates.conf. Add the name of the file you copied to /usr/share/ca-certificates to the top of the list just after the final «#». For example:

# This file lists certificates that you wish to use or to ignore to be
# installed in /etc/ssl/certs.
# update-ca-certificates(8) will update /etc/ssl/certs by reading this file.
#
# This is autogenerated by dpkg-reconfigure ca-certificates.
# certificates shoule be installed under /usr/share/ca-certificates
# and files with extension '.crt' is recognized as available certs.
#
# line begins with # is comment.
# line begins with ! is certificate filename to be deselected.
#
mycert.crt
brasil.gov.br/brasil.gov.br.crt
cacert.org/cacert.org.crt
mozilla/ABAecom_=sub.__Am._Bankers_Assn.=_Root_CA.crt
[... many additional certificates omitted ...]

Instead of manually editing this file, you can run

sudo dpkg-reconfigure ca-certificates

3. Update the CA certificates database by typing:

$ sudo update-ca-certificates

4. You have successfully imported your certificate into the system CA certificates database.

Configuring Apache for SSL Support

To configure Apache2 for HTTPS and generate a certificate, follow the instructions in Server Guide — HTTPD and Server Guide — Certificates.

Resources

Additional resources pertaining to OpenSSL and Secure Sockets Layer appear below.

Local System Resources

man config

System manual page for the OpenSSL library configuration files

man gendsa

System manual page for the gendsa DSA private key generator

man genrsa

System manual page for the genrsa RSA private key generator

man openssl

System manual page for the openssl command-line tool

man rand

System manual page for the rand pseudo-random byte generator utility

man x509

System manual page for the x509 certificate display and signing utility

WWW Resources

CACert, a FREE X.509 Certificate Authority

OpenSSL Website

Public Key Infrastructure (X.509) (pkix)


CategorySecurity CategorySecurity CategorySecurity

Понравилась статья? Поделить с друзьями:
  • Кутасепт инструкция по применению цена отзывы аналоги
  • Классификация стилей руководства таблица
  • Супер твистер тренажер инструкция по применению
  • Cooking simulator руководство
  • Налоговый отчет руководства