diff options
author | Timo Teräs <timo.teras@iki.fi> | 2013-12-31 13:43:38 +0200 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2013-12-31 13:44:51 +0200 |
commit | 94998965c2563e48e8ce172ac6b3a3db819740f8 (patch) | |
tree | a2af073e06cf5a601c6f36c055503e528cd97e77 /main/openssl | |
parent | f9b9fff33279f090d6d32345a12f28562db3f137 (diff) | |
download | aports-94998965c2563e48e8ce172ac6b3a3db819740f8.tar.bz2 aports-94998965c2563e48e8ce172ac6b3a3db819740f8.tar.xz |
main/openssl: rewrite c_rehash in C for speed
fixes #2533
Diffstat (limited to 'main/openssl')
-rw-r--r-- | main/openssl/APKBUILD | 16 | ||||
-rw-r--r-- | main/openssl/c_rehash.c | 235 | ||||
-rw-r--r-- | main/openssl/c_rehash.sh | 157 |
3 files changed, 243 insertions, 165 deletions
diff --git a/main/openssl/APKBUILD b/main/openssl/APKBUILD index ca5e5fe649..dcdb703e4b 100644 --- a/main/openssl/APKBUILD +++ b/main/openssl/APKBUILD @@ -1,7 +1,7 @@ # Maintainer: Timo Teras <timo.teras@iki.fi> pkgname=openssl pkgver=1.0.1e -pkgrel=6 +pkgrel=7 pkgdesc="Toolkit for SSL v2/v3 and TLS v1" url="http://openssl.org" depends= @@ -26,7 +26,7 @@ source="http://www.openssl.org/source/${pkgname}-${pkgver}.tar.gz openssl-use-termios.patch openssl-disable-rdrand-default.patch fix-default-apps-capath.patch - c_rehash.sh + c_rehash.c " _builddir="$srcdir"/$pkgname-$pkgver @@ -87,14 +87,14 @@ build() { || return 1 make -j1 || return 1 + + # replace the c_rehash perl script with our C-version + $CC $CFLAGS -I include -L . "$srcdir"/c_rehash.c -o tools/c_rehash -lcrypto || return 1 } package() { cd "$_builddir" make -j1 INSTALL_PREFIX="$pkgdir" MANDIR=/usr/share/man install - # replace the perl script with a shell script - rm -f "$pkgdir"/usr/bin/c_rehash - install -m 755 "$srcdir"/c_rehash.sh "$pkgdir"/usr/bin/c_rehash || return 1 } libcrypto() { @@ -130,7 +130,7 @@ d1f3aaad7c36590f21355682983cd14e openssl-1.0.1-version-eglibc.patch 2681796363085d01db8a81c249cd2d7b openssl-use-termios.patch 8a251d30c977ffe8bfbf9d9b7eae1a8e openssl-disable-rdrand-default.patch efec1bce615256961b1756e575ee1d0a fix-default-apps-capath.patch -d0b39772b0d8bcde609b57dcf4433be8 c_rehash.sh" +f1334f9761e14ccc71931654320653be c_rehash.c" sha256sums="f74f15e8c8ff11aa3d5bb5f276d202ec18d7246e95f961db76054199c69c1ae3 openssl-1.0.1e.tar.gz fe844e21b2c42da2d8e9c89350211d70c0829f45532b89b7e492bfde589ee7ed fix-manpages.patch 82863c2fed659a7186c7f3905a1853b8bd8060350ad101ce159fa7e7d2ba27e8 openssl-bb-basename.patch @@ -143,7 +143,7 @@ cbb2493ec9157e78035e9cc02be17655996ee9cd0a71b79507fc19f3862f452b 0003-engines-e 05266a671143cf17367dee8d409ad6d0857201392c99731d7ebb8f8cdcdc32f7 openssl-use-termios.patch c215b03f9328b8dfb81e3fa90bdf0332d6b649688944ff79fe60be62131ccb60 openssl-disable-rdrand-default.patch 1e11d6b8cdcdd6957c69d33ab670c5918fc96c12fdb9b76b4287cb8f69c3545d fix-default-apps-capath.patch -c99cf6efd66c7515a2a627b4bcf9b08f237401a5e514f12ed300b33c466450ff c_rehash.sh" +1e8a060228221b4746822caf6139261fc1fbf0c9939f1181a9a7bec7ee855490 c_rehash.c" sha512sums="c76857e439431b2ef6f2aa123997e53f82b9c3c964d4d765d7cc6c0c20b37a21adf578f9b759b2b65ae3925454c432a01b7de0cd320ece7181dc292e00d3244e openssl-1.0.1e.tar.gz 880411d56da49946d24328445728367e0bf13b0fd47954971514bee8cd5613a038ad8aeaf68da2c92f4634deb022febd7b3e37f9bbfc5d2c9c8b3b5ffd971407 fix-manpages.patch 6c4f4b0c1b606b3e5a8175618c4398923392f9c25ad8d3f5b65b0424fe51e104c4f456d2da590d9f572382225ab320278e88db1585790092450cad60a02819a5 openssl-bb-basename.patch @@ -156,4 +156,4 @@ b019320869d215014ad46e0b29aa239e31243571c4d45256b3ce6449a67fdc106a381c1cf3abd55d 22261ad902ad4826db889fa0e6196b57d6cb389c1707f5827ba48a4630097e590979257f16f4a36fe611199fa33ba32d5f412c8b93beb84001865c2501b288da openssl-use-termios.patch 2af7a40d023e4a09c14712661056a45c572416d5bbee8d90caf5d9d44854ffa86b1d3a0bebf78156ec5da2e71ae91724c007c3d0a8de5f025b3947fd0add287d openssl-disable-rdrand-default.patch f2e737146a473d55b99f27457718ca299a02a0c74009026a30c3d1347c575bc264962b5708995e02ef7d68521b8366ccea7320523efb87b1ab2632d73fec5658 fix-default-apps-capath.patch -ad4dde3ad0abee7645b1ab3111242f045cc381e4381a19dd0c624059697cb0f6486f8463da6dfb22f11d9b2882a1872fef8a1fd1709b0981847d0a6d2c8741a3 c_rehash.sh" +cb2a1240d8d615ea20f0aeb00149f422d934edd0d4a149badf2b8f11ab375cd208a34430f7616971785560d81659ebf81cc7ffe1cdb2ac43650c0005ecbc6aa0 c_rehash.c" diff --git a/main/openssl/c_rehash.c b/main/openssl/c_rehash.c new file mode 100644 index 0000000000..a46ec4533c --- /dev/null +++ b/main/openssl/c_rehash.c @@ -0,0 +1,235 @@ +/* c_rehash.c - C implementation based on the Perl and shell versions + * + * Copyright (c) 2013 Timo Teräs <timo.teras@iki.fi> + * All rights reserved. + * + * This software is licensed under the MIT License. + * Full license available at: http://opensource.org/licenses/MIT + */ + +#define _POSIX_C_SOURCE 200809L +#define _GNU_SOURCE +#include <ctype.h> +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <dirent.h> +#include <fnmatch.h> + +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +#define countof(x) (sizeof(x) / sizeof(x[0])) + +struct hash_info { + struct hash_info *next; + int type; + unsigned long hash; + unsigned char digest[EVP_MAX_MD_SIZE]; +}; + +enum Type { + TYPE_CERT = 0, + TYPE_CRL, + MAX_TYPES, +}; + +static const EVP_MD *evpmd; +static int evpmdsize; +static const char *prefixes[MAX_TYPES] = { "", "r" }; +static struct hash_info *hash_table[257]; + +static int get_link_id(int type, unsigned long hash, unsigned char *digest) +{ + unsigned int bucket = hash % countof(hash_table); + struct hash_info *hi; + int count = 0; + + for (hi = hash_table[bucket]; hi; hi = hi->next) { + if (hi->type != type || hi->hash != hash) + continue; + if (memcmp(digest, hi->digest, evpmdsize) == 0) + return -1; + count++; + } + + hi = malloc(sizeof(*hi)); + hi->next = hash_table[bucket]; + hi->type = type; + hi->hash = hash; + memcpy(hi->digest, digest, evpmdsize); + hash_table[bucket] = hi; + + return count; +} + +static int link_file(int dirfd, const char *filename, int type, unsigned long hash, unsigned char *digest) +{ + char linkfn[32]; + int id; + + id = get_link_id(type, hash, digest); + if (id < 0) { + fprintf(stderr, "WARNING: Skipping duplicate certificate in file %s\n", + filename); + return -1; + } + + snprintf(linkfn, sizeof(linkfn), + "%08lx.%s%d", hash, prefixes[type], id); + fprintf(stdout, "%s => %s\n", linkfn, filename); + if (symlinkat(filename, dirfd, linkfn) < 0) + perror(linkfn); + + return 0; +} + +static BIO *BIO_openat(int dirfd, const char *filename) +{ + FILE *fp; + BIO *bio; + int fd; + + fd = openat(dirfd, filename, O_RDONLY); + if (fd < 0) { + perror(filename); + return NULL; + } + fp = fdopen(fd, "r"); + if (fp == NULL) { + close(fd); + return NULL; + } + bio = BIO_new_fp(fp, BIO_CLOSE); + if (!bio) { + fclose(fp); + return NULL; + } + return bio; +} + +static int hash_file(int dirfd, const char *filename) +{ + STACK_OF(X509_INFO) *inf; + X509_INFO *x; + BIO *b; + int i, count = 0; + unsigned char digest[EVP_MAX_MD_SIZE]; + + b = BIO_openat(dirfd, filename); + if (!b) + return -1; + + inf = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL); + BIO_free(b); + if (!inf) + return -1; + + for(i = 0; i < sk_X509_INFO_num(inf); i++) { + x = sk_X509_INFO_value(inf, i); + if (x->x509) { + X509_digest(x->x509, evpmd, digest, NULL); + link_file(dirfd, filename, TYPE_CERT, + X509_subject_name_hash(x->x509), digest); + count++; + } + if (x->crl) { + X509_CRL_digest(x->crl, evpmd, digest, NULL); + link_file(dirfd, filename, TYPE_CRL, + X509_NAME_hash(X509_CRL_get_issuer(x->crl)), + digest); + count++; + } + } + sk_X509_INFO_pop_free(inf, X509_INFO_free); + + if (count == 0) { + fprintf(stderr, + "WARNING: %s does not contain a certificate or CRL: skipping\n", + filename); + } + + return count; +} + +static int is_hash_filename(const char *fn) +{ + int i; + + for (i = 0; i < 8; i++) + if (!isxdigit(fn[i])) + return 0; + if (fn[i++] != '.') + return 0; + if (fn[i] == 'r') i++; + for (; fn[i] != 0; i++) + if (!isdigit(fn[i])) + return 0; + return 1; +} + +static int hash_dir(const char *dirname) +{ + struct dirent *de; + struct stat st; + int dirfd; + DIR *d; + + fprintf(stdout, "Doing %s\n", dirname); + dirfd = open(dirname, O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + perror(dirname); + return -1; + } + d = opendir(dirname); + if (!d) { + close(dirfd); + return -1; + } + while ((de = readdir(d)) != NULL) { + if (fstatat(dirfd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + continue; + if (!S_ISLNK(st.st_mode)) + continue; + if (!is_hash_filename(de->d_name)) + continue; + + if (unlinkat(dirfd, de->d_name, 0) < 0) + perror(de->d_name); + } + + rewinddir(d); + while ((de = readdir(d)) != NULL) { + if (fnmatch("*.pem", de->d_name, FNM_NOESCAPE) == 0) + hash_file(dirfd, de->d_name); + } + closedir(d); + + return 0; +} + +int main(int argc, char **argv) +{ + const char *env; + int i; + + evpmd = EVP_sha1(); + evpmdsize = EVP_MD_size(evpmd); + + if (argc > 1) { + for (i = 1; i < argc; i++) + hash_dir(argv[i]); + } else if ((env = getenv("SSL_CERT_DIR")) != NULL) { + char *e, *m; + m = strdup(env); + for (e = strtok(m, ":"); e != NULL; e = strtok(NULL, ":")) + hash_dir(e); + free(m); + } else { + hash_dir("/etc/ssl/certs"); + } + + return 0; +} diff --git a/main/openssl/c_rehash.sh b/main/openssl/c_rehash.sh deleted file mode 100644 index 9840132d22..0000000000 --- a/main/openssl/c_rehash.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/bin/sh -# -# Ben Secrest <blsecres@gmail.com> -# -# sh c_rehash script, scan all files in a directory -# and add symbolic links to their hash values. -# -# based on the c_rehash perl script distributed with openssl -# -# LICENSE: See OpenSSL license -# ^^acceptable?^^ -# - -# default certificate location -DIR=/etc/openssl - -# -# use openssl to fingerprint a file -# arguments: -# 1. the filename to fingerprint -# 2. the method to use (x509, crl) -# returns: -# none -# assumptions: -# user will capture output from last stage of pipeline -# -fingerprint() -{ - ${SSL_CMD} ${2} -fingerprint -noout -in ${1} | sed -e 's/^.*=//' -e 's/://g' -} - - -# -# link_hash - create links to certificate files -# arguments: -# 1. the filename to create a link for -# 2. the type of certificate being linked (x509, crl) -# returns: -# 0 on success, 1 otherwise -# -link_hash() -{ - local HASH=$( ${SSL_CMD} ${2} -hash -noout -in ${1} ) - local SUFFIX=0 - local LINKFILE='' - local TAG='' - - if [ ${2} = "crl" ] - then - TAG='r' - fi - - LINKFILE=${HASH}.${TAG}${SUFFIX} - - if [ -f ${LINKFILE} ] - then - local FINGERPRINT=$( fingerprint ${1} ${2} ) - - while [ -f ${LINKFILE} ] - do - if [ ${FINGERPRINT} = $( fingerprint ${LINKFILE} ${2} ) ] - then - echo "WARNING: Skipping duplicate file ${1}" >&2 - return 1 - fi - - SUFFIX=$(( ${SUFFIX} + 1 )) - LINKFILE=${HASH}.${TAG}${SUFFIX} - done - fi - - echo "${1} => ${LINKFILE}" - - # assume any system with a POSIX shell will either support symlinks or - # do something to handle this gracefully - ln -s ${1} ${LINKFILE} - - return 0 -} - - -# hash_dir create hash links in a given directory -hash_dir() -{ - echo "Doing ${1}" - - cd ${1} - - ls -1 * 2>/dev/null | grep -E '^[[:xdigit:]]{8}\.r?[[:digit:]]+$' | while read FILE - do - [ -h "${FILE}" ] && rm "${FILE}" - done - - ls -1 *.pem 2>/dev/null | while read FILE - do - local TYPE_STR= - - if grep -q '^-----BEGIN X509 CRL-----' ${FILE}; then - TYPE_STR="crl" - elif grep -q -E '^-----BEGIN (X509 |TRUSTED )?CERTIFICATE-----' ${FILE}; then - TYPE_STR="x509" - else - echo "WARNING: ${FILE} does not contain a certificate or CRL: skipping" >&2 - continue - fi - - link_hash ${FILE} ${TYPE_STR} - done -} - - -# choose the name of an ssl application -if [ -n "${OPENSSL}" ] -then - SSL_CMD=$(which ${OPENSSL} 2>/dev/null) -else - SSL_CMD=/usr/bin/openssl - OPENSSL=${SSL_CMD} - export OPENSSL -fi - -# fix paths -PATH=${PATH}:${DIR}/bin -export PATH - -# confirm existance/executability of ssl command -if ! [ -x ${SSL_CMD} ] -then - echo "${0}: rehashing skipped ('openssl' program not available)" >&2 - exit 0 -fi - -# determine which directories to process -old_IFS=$IFS -if [ ${#} -gt 0 ] -then - IFS=':' - DIRLIST=${*} -elif [ -n "${SSL_CERT_DIR}" ] -then - DIRLIST=$SSL_CERT_DIR -else - DIRLIST=${DIR}/certs -fi - -IFS=':' - -# process directories -for CERT_DIR in ${DIRLIST} -do - if [ -d ${CERT_DIR} -a -w ${CERT_DIR} ] - then - IFS=$old_IFS - hash_dir ${CERT_DIR} - IFS=':' - fi -done |