1

I recently started using HKPK Public Key Pinning.

I have an automated script that generates my csr, certificate, and installs into apache2 on opensuse leap 42.3

I'm looking for a way to add spki fingerprints to the Public Key Pin header in my VirtualHost file.

I generate the fingerprint with:

openssl x509 -pubkey < certificate.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64

I need to auto add:

pin-sha256=\"spki_fingerprint_here\";

I need to do this without completely rewriting the whole line so the pin-sha256 values in front stay and the config:

max-age=345600; includeSubDomains"

...at the end stays where it is ^^.

The whole line looks like:

Header set Public-Key-Pins "pin-sha256=\"spki_fingerprint1\"; pin-sha256=\"spki_fingerprint2\"; pin-sha256=\"new_spki_fingerprint_added_here\"; max-age=2592000; includeSubDomains"

I'm not a programmer or linux 'expert'

Any advice that can lead me in the right direction would be very helpful. Thank you in advance.

Bennett
  • 11
  • 2

2 Answers2

0

Here I search for max-age, assuming it is found only once in the file.

perl -i -lape "s/(.*)( max-age.*)/\$1 <substitute-string> \$2/" virtualhost.conf

Where the substitute string can be written as:

pin-sha256=\\\\\"$(openssl x509 -pubkey < certificate.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)\\\\\"\$2

Answer:

Putting together the fingerprint generation with the substitution command, you get:

perl -i -lape "s/(.*)( max-age.*)/\$1 pin-sha256=\\\\\"$(openssl x509 -pubkey < certificate.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64)\\\\\"\$2/" virtualhost.conf

Note:

Double quotes around the perl instruction are required in order for the fingerprint generating command to be executed. They make a lot of escaping \ necessary.

simlev
  • 1,105
  • 3
  • 14
  • 22
  • Thank you. I much prefer your one liner though there are multiple lines in the conf file with max-age though, Public-Key-Pins is only in the one line – Bennett Aug 01 '18 at 23:06
  • Easy then, just add `if /Public-Key-Pins/` as you probably already figured out . – simlev Aug 02 '18 at 20:57
0

A friend of mine wrote me a script to perform this function.

#/usr/bin/perl
use strict;
use warnings;

my $inputFile = "sample.conf";
my $outputFile = "sample.conf.modified";

my $searchString = "Header set Public-Key-Pins";
my $updateString = "      Header set Public-Key-Pins ";

my $numberOfPins = $#ARGV + 1;

if ($numberOfPins < 1) {
  die "Error: Minimum 1 command line argument required";
}

my $pinCounter = 1;
my $onePin;

foreach my $argNum (0 .. $#ARGV) {
  $onePin = $ARGV[$argNum];

  if ($pinCounter == "1") {
    $updateString = $updateString . "\"";
  }

  $updateString = $updateString . "pin-sha256=\\\"$onePin\\\"";

  if ($pinCounter < $numberOfPins) {
    $updateString = $updateString . "; ";
  }
  else {
    $updateString = $updateString . "; max-age=000000; includeSubDomains\"";
  }
  ++$pinCounter;
}

open INFILE, $inputFile or die "Can't read from $inputFile!\n";

my $numberOfMatches = 0;

my @lines;
while (my $line = <INFILE>) {
    if (index($line, $searchString) != -1) {
        push @lines, "$updateString\n";
        ++$numberOfMatches;
    } else {
        push @lines, $line;
    }
}
close INFILE;

open OUTFILE, '>', $outputFile or die "Can't write to $outputFile!\n";
print OUTFILE @lines;
close OUTFILE;

if ($numberOfMatches != "1") {
  die "Error: expected 1 match but found: $numberOfMatches matches\n";
}
Bennett
  • 11
  • 2