Как разделить файл PEM

38

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

Вопрос: Как прочитать сцепленный PEM-файл как файл, используемый директивой apache / mod_ssl SSLCACertificateFile ?

Ответ (оригинал) ( источник ):

cat $file|awk 'split_after==1{n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1} {print > "cert" n ".pem"}'

Это может оставить пустой файл, если в конце есть пустая строка, например, с openssl pkcs7 -outform PEM -in my-chain-file -print_certs. Чтобы предотвратить это, проверьте длину строки перед печатью:

cat $file|awk 'split_after==1{n++;split_after=0}
   /-----END CERTIFICATE-----/ {split_after=1}
   {if(length($0) > 0) print > "cert" n ".pem"}' 

Ответ 29/03/2016 :

После @slugchewer ответа , csplitможет быть понятнее вариант с:

csplit -f cert- $file '/-----BEGIN CERTIFICATE-----/' '{*}'
Cerber
источник
Это может быть глупый вопрос, но зачем мне разделять файл pem?
Ашвани Агарвал
6
@AshwaniAgarwal Вы хотите разделить файл PEM, если он содержит несколько сертификатов, и вы хотите проверить сертификаты по отдельности с помощью таких инструментов, как openssl, например , один сертификат для анализа.
Закон 29
Кроме того, некоторые инструменты или серверы хотят объединенный файл с сертификатом и ключом, в то время как другие хотят, чтобы они были отдельными.
Captncraig
Мне пришлось добавить «% ----- BEGIN CERTIFICATE -----%» в командную строку csplit, чтобы предотвратить пустой файл. Кажется, соответствует тому, что указывает справочная страница: csplit -f ./tmp/cert- $ file '% ----- BEGIN CERTIFICATE -----%' '/ ----- BEGIN CERTIFICATE ----- / '' {*} '
Крейг Хикс,
2
используйте "csplit -z", чтобы не оставлять пустых файлов.
Пол М

Ответы:

23

Фрагмент awk работает для извлечения различных частей, но вам все равно нужно знать, какой раздел является ключом / сертификатом / цепочкой. Мне нужно было извлечь конкретный раздел и найти его в списке рассылки OpenSSL: http://openssl.6102.n7.nabble.com/Convert-pem-to-crt-and-key-files-tp47681p47697.html

# Extract key
openssl pkey -in foo.pem -out foo-key.pem

# Extract all the certs
openssl crl2pkcs7 -nocrl -certfile foo.pem |
  openssl pkcs7 -print_certs -out foo-certs.pem

# Extract the textually first cert as DER
openssl x509 -in foo.pem -outform DER -out first-cert.der
Йоханнес Фиш Зимке
источник
хороший набор команд :) Я оставлю его для будущего использования, но в моем случае использования выше, я работаю с файлом только для сертификатов, содержащим 50+ сертификатов CA ==> без pkey и цепочки
Cerber
2
Я думаю, что это лучше, чем решение awk, пусть openssl выполняет синтаксический анализ + вы получаете преобразование.
Расти
Извините, но только команда pkey верна. Второе и третье не делают то, что вы рекламируете - они делают что-то другое. В некоторых случаях результат хороший, в некоторых случаях он может вызвать таинственное поведение у потребителей. Отредактировано немного.
Кубанчик
Есть идеи, как получить текстовый 3-й сертификат таким образом?
мерцание
16

Ранее на StackOverflow был дан ответ :

awk '
  split_after == 1 {n++;split_after=0}
  /-----END CERTIFICATE-----/ {split_after=1}
  {print > "cert" n ".pem"}' < $file

Изменить 29/03/2016 : см. Ответ @slugchewer

Cerber
источник
Работает только на Linux, не работает на FreeBSD.
Майкл-О
3
Вдохновленный этим, я создал сценарий awk, который разбивает сертификаты и ключи на отдельные файлы: gist.github.com/jinnko/d6867ce326e8b6e88975
JinnKo
15

Команда splitдоступна в большинстве систем, и ее вызов, вероятно, легче запомнить.

Если у вас есть файл, collection.pemкоторый вы хотите разбить на individual-*файлы, используйте:

split -p "-----BEGIN CERTIFICATE-----" collection.pem individual-

Если у вас нет split, вы можете попробовать csplit:

csplit -f individual- collection.pem '/-----BEGIN CERTIFICATE-----/' '{*}'
squidpickles
источник
2
Извините, ни одна из моих систем (busybox, fedora, centos) не отображает -pопцию (ни страницы, которые я читаю ) на split. Может быть, вы используете специальный бинарный файл / пакет
Cerber
1
@Cerber Могу попробовать csplitвместо этого ... (см.
Правку
1
отлично работает с csplit!
Цербер
На FreeBSD я получаю из csplit: csplit: *}: bad repetition count(но похоже, что split работает)
Гвинет Ллевелин
4

Если вы хотите получить один сертификат из пакета PEM с несколькими сертификатами, попробуйте:

$ openssl crl2pkcs7 -nocrl -certfile INPUT.PEM | \
    openssl pkcs7 -print_certs | \
    awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/'
  • Первые две opensslкоманды обработают файл PEM и выплюнут его с префиксами "subject:"и "issuer:"строками перед каждым сертификатом. Если ваш PEM уже отформатирован таким образом, вам нужна только последняя awkкоманда.
  • Команда awk выдаст отдельный PEM, соответствующий строке CN (общее имя).

источник1 , источник2

cmcginty
источник
Я не вижу этого в вашем источнике. Кроме того, PEM в кодировке Base64, вы не найдете текст, такой как "subject", "CN", ... с awk
Cerber
1
Да, это не работает для каждого типа PEM. Если вы извлекаете P7B в PEM с помощью openssl, перед каждым сертификатом будет указана строка темы. Или вы можете изменить любую строку, с которой вы сегментируете свой файл PEM.
cmcginty
Обновленный ответ для обработки, когда PEM не содержит "subject"
cmcginty
3

Также стоит отметить, что PEM-файлы - это просто набор ключей / сертификатов внутри BEGIN/ ENDблоков, так что довольно просто вырезать / вставить, если это всего лишь один файл с одним или двумя интересными объектами ...

mgalgs
источник
2

Если вы обрабатываете сертификаты с полной цепочкой (т. Е. Сгенерированные letsencrypt / certbot и т. Д.), Которые являются объединением сертификата и цепочки центра сертификации, вы можете использовать манипуляцию строк bash.

Например:

# content of /path/to/fullchain.pem
-----BEGIN CERTIFICATE-----
some long base64 string containing
the certificate
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
another base64 string
containing the first certificate
in the authority chain
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
another base64 string
containing the second certificate
in the authority chain
(there might be more...)
-----END CERTIFICATE-----

Чтобы извлечь сертификат и цепочку центра сертификации в переменные:

# load the certificate into a variable
FULLCHAIN=$(</path/to/fullchain.pem)
CERTIFICATE="${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----"
CHAIN=$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d')

Объяснение:

Вместо использования awk или openssl (которые являются мощными инструментами, но не всегда доступны, например, в изображениях Docker Alpine), вы можете использовать манипуляции со строками bash.

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----": от конца содержимого FULLCHAIN, вернуть самое длинное совпадение подстроки, затем concat, -----END CERTIFICATE-----когда оно будет удалено. Соответствует *всем персонажам после -----END CERTIFICATE-----.

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'): с начала содержимого FULLCHAIN, верните самое короткое совпадение подстроки, затем удалите начальные строки. Аналогично, *соответствует всем персонажам раньше -----END CERTIFICATE-----.

Для быстрого ознакомления (хотя вы можете узнать больше о работе со строками в bash здесь ):

${VAR#substring}= самая короткая подстрока от начала содержимого VAR

${VAR%substring}= самая короткая подстрока из конца содержимого VAR

${VAR##substring}= самая длинная подстрока от начала содержимого VAR

${VAR%%substring}= самая длинная подстрока из конца содержимого VAR

Fabio
источник
Если вы не слишком разбираетесь в bash, когда вы выводите эти переменные, окружите переменную кавычками, чтобы сохранить разрывы строк, как вы привыкли их видеть. Я помню, когда это было не так очевидно для меня. Фабио, сладкое использование манипуляций со струнами баш!
мерцание
0

Хммм ... почти так же, как я подготовил решение (как предложено y @Cerber), не осознавая, что эта ситуация, похоже, есть у многих людей. Мое решение следует почти той же логике, но использует несколько более простых команд:

Все мои сертификаты находятся в файле: certin.pem

c=0
while read line
  do
    if echo $line | grep END; then
    echo $line >> certout$c.pem
    c=`expr $c + 1`
    else
     echo $line
     echo $line >> certout$c.pem
    fi
done < /tmp/certin.pem

Это, в основном, сохраняет запись в файл до тех пор, пока не встретит «END», а затем начнет запись в другой файл в увеличенном виде. Таким образом, у вас будет «N» количество файлов выходных файлов ( certout0.pem, certout1.pem и т. Д.) В зависимости от того, сколько сертификатов содержится во входном файле pem ( certin.pem ).

Ашиш К Шривастава
источник