libressl: use the C c_rehash tool written by Timo Teras via Alpine.
Thanks to Timo Teras for doing the hard work!
This commit is contained in:
parent
14eac4987a
commit
04251ee7fe
|
@ -1,180 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
|
||||
# Perl c_rehash script, scan all files in a directory
|
||||
# and add symbolic links to their hash values.
|
||||
|
||||
my $openssl;
|
||||
|
||||
my $dir = "/etc/ssl";
|
||||
my $prefix = "/usr";
|
||||
|
||||
if(defined $ENV{OPENSSL}) {
|
||||
$openssl = $ENV{OPENSSL};
|
||||
} else {
|
||||
$openssl = "openssl";
|
||||
$ENV{OPENSSL} = $openssl;
|
||||
}
|
||||
|
||||
my $pwd;
|
||||
eval "require Cwd";
|
||||
if (defined(&Cwd::getcwd)) {
|
||||
$pwd=Cwd::getcwd();
|
||||
} else {
|
||||
$pwd=`pwd`; chomp($pwd);
|
||||
}
|
||||
my $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':'; # DOS/Win32 or Unix delimiter?
|
||||
|
||||
$ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : ""); # prefix our path
|
||||
|
||||
if(! -x $openssl) {
|
||||
my $found = 0;
|
||||
foreach (split /$path_delim/, $ENV{PATH}) {
|
||||
if(-x "$_/$openssl") {
|
||||
$found = 1;
|
||||
$openssl = "$_/$openssl";
|
||||
last;
|
||||
}
|
||||
}
|
||||
if($found == 0) {
|
||||
print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n";
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(@ARGV) {
|
||||
@dirlist = @ARGV;
|
||||
} elsif($ENV{SSL_CERT_DIR}) {
|
||||
@dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR};
|
||||
} else {
|
||||
$dirlist[0] = "$dir/certs";
|
||||
}
|
||||
|
||||
if (-d $dirlist[0]) {
|
||||
chdir $dirlist[0];
|
||||
$openssl="$pwd/$openssl" if (!-x $openssl);
|
||||
chdir $pwd;
|
||||
}
|
||||
|
||||
foreach (@dirlist) {
|
||||
if(-d $_ and -w $_) {
|
||||
hash_dir($_);
|
||||
}
|
||||
}
|
||||
|
||||
sub hash_dir {
|
||||
my %hashlist;
|
||||
print "Doing $_[0]\n";
|
||||
chdir $_[0];
|
||||
opendir(DIR, ".");
|
||||
my @flist = readdir(DIR);
|
||||
# Delete any existing symbolic links
|
||||
foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
|
||||
if(-l $_) {
|
||||
unlink $_;
|
||||
}
|
||||
}
|
||||
closedir DIR;
|
||||
FILE: foreach $fname (grep {/\.pem$/} @flist) {
|
||||
# Check to see if certificates and/or CRLs present.
|
||||
my ($cert, $crl) = check_file($fname);
|
||||
if(!$cert && !$crl) {
|
||||
print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
|
||||
next;
|
||||
}
|
||||
link_hash_cert($fname) if($cert);
|
||||
link_hash_crl($fname) if($crl);
|
||||
}
|
||||
}
|
||||
|
||||
sub check_file {
|
||||
my ($is_cert, $is_crl) = (0,0);
|
||||
my $fname = $_[0];
|
||||
open IN, $fname;
|
||||
while(<IN>) {
|
||||
if(/^-----BEGIN (.*)-----/) {
|
||||
my $hdr = $1;
|
||||
if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
|
||||
$is_cert = 1;
|
||||
last if($is_crl);
|
||||
} elsif($hdr eq "X509 CRL") {
|
||||
$is_crl = 1;
|
||||
last if($is_cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
close IN;
|
||||
return ($is_cert, $is_crl);
|
||||
}
|
||||
|
||||
|
||||
# Link a certificate to its subject name hash value, each hash is of
|
||||
# the form <hash>.<n> where n is an integer. If the hash value already exists
|
||||
# then we need to up the value of n, unless its a duplicate in which
|
||||
# case we skip the link. We check for duplicates by comparing the
|
||||
# certificate fingerprints
|
||||
|
||||
sub link_hash_cert {
|
||||
my $fname = $_[0];
|
||||
$fname =~ s/'/'\\''/g;
|
||||
my ($hash, $fprint) = `"$openssl" x509 -hash -fingerprint -noout -in "$fname"`;
|
||||
chomp $hash;
|
||||
chomp $fprint;
|
||||
$fprint =~ s/^.*=//;
|
||||
$fprint =~ tr/://d;
|
||||
my $suffix = 0;
|
||||
# Search for an unused hash filename
|
||||
while(exists $hashlist{"$hash.$suffix"}) {
|
||||
# Hash matches: if fingerprint matches its a duplicate cert
|
||||
if($hashlist{"$hash.$suffix"} eq $fprint) {
|
||||
print STDERR "WARNING: Skipping duplicate certificate $fname\n";
|
||||
return;
|
||||
}
|
||||
$suffix++;
|
||||
}
|
||||
$hash .= ".$suffix";
|
||||
print "$fname => $hash\n";
|
||||
$symlink_exists=eval {symlink("",""); 1};
|
||||
if ($symlink_exists) {
|
||||
symlink $fname, $hash;
|
||||
} else {
|
||||
open IN,"<$fname" or die "can't open $fname for read";
|
||||
open OUT,">$hash" or die "can't open $hash for write";
|
||||
print OUT <IN>; # does the job for small text files
|
||||
close OUT;
|
||||
close IN;
|
||||
}
|
||||
$hashlist{$hash} = $fprint;
|
||||
}
|
||||
|
||||
# Same as above except for a CRL. CRL links are of the form <hash>.r<n>
|
||||
|
||||
sub link_hash_crl {
|
||||
my $fname = $_[0];
|
||||
$fname =~ s/'/'\\''/g;
|
||||
my ($hash, $fprint) = `"$openssl" crl -hash -fingerprint -noout -in '$fname'`;
|
||||
chomp $hash;
|
||||
chomp $fprint;
|
||||
$fprint =~ s/^.*=//;
|
||||
$fprint =~ tr/://d;
|
||||
my $suffix = 0;
|
||||
# Search for an unused hash filename
|
||||
while(exists $hashlist{"$hash.r$suffix"}) {
|
||||
# Hash matches: if fingerprint matches its a duplicate cert
|
||||
if($hashlist{"$hash.r$suffix"} eq $fprint) {
|
||||
print STDERR "WARNING: Skipping duplicate CRL $fname\n";
|
||||
return;
|
||||
}
|
||||
$suffix++;
|
||||
}
|
||||
$hash .= ".r$suffix";
|
||||
print "$fname => $hash\n";
|
||||
$symlink_exists=eval {symlink("",""); 1};
|
||||
if ($symlink_exists) {
|
||||
symlink $fname, $hash;
|
||||
} else {
|
||||
system ("cp", $fname, $hash);
|
||||
}
|
||||
$hashlist{$hash} = $fprint;
|
||||
}
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
/* 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 <sys/stat.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;
|
||||
}
|
|
@ -11,6 +11,9 @@ homepage="http://www.libressl.org/"
|
|||
distfiles="http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/${pkgname}-${version}.tar.gz"
|
||||
checksum=fb5ada41a75b31c8dd9ff013daca57b253047ad14e43f65d8b41879b7b8e3c17
|
||||
|
||||
post_build() {
|
||||
$CC -Wall $CFLAGS -Iinclude -Lcrypto/.libs $LDFLAGS ${FILESDIR}/c_rehash.c -o ${wrksrc}/c_rehash -lcrypto
|
||||
}
|
||||
post_install() {
|
||||
vlicense COPYING
|
||||
mv ${DESTDIR}/usr/share/man/man1/{passwd.1,libressl-passwd.1}
|
||||
|
@ -30,15 +33,13 @@ libressl-devel_package() {
|
|||
}
|
||||
libressl-openssl_package() {
|
||||
short_desc+=" - utilities"
|
||||
# required by c_rehash
|
||||
depends="perl"
|
||||
provides="openssl-${version}_${revision} openssl-crehash-${version}_${revision}"
|
||||
replaces="libressl<2.0.1_2 openssl>=0 openssl-crehash>=0"
|
||||
provides="openssl-${version}_${revision}"
|
||||
replaces="libressl<2.0.1_2 openssl>=0"
|
||||
conf_files="/etc/ssl/openssl.cnf"
|
||||
pkg_install() {
|
||||
vinstall ${FILESDIR}/openssl.cnf 644 etc/ssl
|
||||
vmove usr/bin
|
||||
vmove usr/share/man/man1
|
||||
vbin ${FILESDIR}/c_rehash
|
||||
vbin ${wrksrc}/c_rehash
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue