| #!/bin/sh |
| |
| # Copyright 2014 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # The following documentation uses the annotation approach from RFC 4158. |
| # CAs (entities that share the same name and public key) are denoted in boxes, |
| # while the indication that a CA Foo signed a certificate for CA Bar is denoted |
| # by directed arrows. |
| # |
| # +---+ +-----+ |
| # | D | | E | |
| # +---+ +-----+ |
| # | | | |
| # +--v v--+ | |
| # +---+ +---+ |
| # | C | | F | |
| # +---+ +---+ |
| # | | |
| # v v---+ |
| # +-----+ |
| # | B | |
| # +-----+ |
| # | |
| # v |
| # +---+ |
| # | A | |
| # +---+ |
| # |
| # To validate A, there are several possible paths, using A(B) to indicate |
| # the certificate A signed by B: |
| # |
| # 1. A(B) -> B(C) -> C(D) -> D(D) |
| # 3. A(B) -> B(C) -> C(E) -> E(E) |
| # 4. A(B) -> B(F) -> F(E) -> E(E) |
| # |
| # That is, there are two different versions of C (signed by D and E) and |
| # two versions of B (signed by C and F). Possible trust anchors are D and E, |
| # which are both self-signed. |
| # |
| # The goal is to ensure that, as long as at least one of C or F is still valid, |
| # clients are able to successfully build a valid path. |
| |
| # Exit script as soon a something fails. |
| set -e |
| |
| rm -rf out |
| mkdir out |
| |
| echo Create the serial and index number files. |
| for i in B C D E F |
| do |
| openssl rand -hex -out "out/${i}-serial" 16 |
| touch "out/${i}-index.txt" |
| done |
| |
| echo Generate the keys. |
| for i in A B C D E F |
| do |
| openssl genrsa -out "out/${i}.key" 2048 |
| done |
| |
| echo "Generating the self-signed roots" |
| for i in D E |
| do |
| echo "Generating CSR ${i}" |
| CA_COMMON_NAME="${i} Root CA - Multi-root" \ |
| CERTIFICATE="${i}" \ |
| openssl req \ |
| -config redundant-ca.cnf \ |
| -new \ |
| -key "out/${i}.key" \ |
| -out "out/${i}.csr" |
| |
| echo "Generating self-signed ${i}" |
| CA_COMMON_NAME="${i} Root CA - Multi-root" \ |
| CERTIFICATE="${i}" \ |
| openssl ca \ |
| -config redundant-ca.cnf \ |
| -batch \ |
| -startdate 160102000000Z \ |
| -enddate 260102000000Z \ |
| -extensions ca_cert \ |
| -extfile redundant-ca.cnf \ |
| -selfsign \ |
| -in "out/${i}.csr" \ |
| -out "out/${i}.pem" |
| done |
| |
| echo "Generating intermediate CSRs" |
| for i in B C F |
| do |
| echo "Generating CSR ${i}" |
| CA_COMMON_NAME="${i} CA - Multi-root" \ |
| CERTIFICATE="${i}" \ |
| openssl req \ |
| -config redundant-ca.cnf \ |
| -new \ |
| -key "out/${i}.key" \ |
| -out "out/${i}.csr" |
| done |
| |
| echo D signs C |
| CA_COMMON_NAME="D CA - Multi-root" \ |
| CERTIFICATE=D \ |
| openssl ca \ |
| -config redundant-ca.cnf \ |
| -batch \ |
| -startdate 160103000000Z \ |
| -enddate 260102000000Z \ |
| -extensions ca_cert \ |
| -extfile redundant-ca.cnf \ |
| -in out/C.csr \ |
| -out out/C.pem |
| |
| echo C signs B |
| CA_COMMON_NAME="C CA - Multi-root" \ |
| CERTIFICATE=C \ |
| openssl ca \ |
| -config redundant-ca.cnf \ |
| -batch \ |
| -startdate 160104000000Z \ |
| -enddate 260102000000Z \ |
| -extensions ca_cert \ |
| -extfile redundant-ca.cnf \ |
| -in out/B.csr \ |
| -out out/B.pem |
| |
| echo E signs C2 |
| CA_COMMON_NAME="E CA - Multi-root" \ |
| CERTIFICATE=E \ |
| openssl ca \ |
| -config redundant-ca.cnf \ |
| -batch \ |
| -startdate 160105000000Z \ |
| -enddate 260102000000Z \ |
| -extensions ca_cert \ |
| -extfile redundant-ca.cnf \ |
| -in out/C.csr \ |
| -out out/C2.pem |
| |
| echo E signs F |
| CA_COMMON_NAME="E CA - Multi-root" \ |
| CERTIFICATE=E \ |
| openssl ca \ |
| -config redundant-ca.cnf \ |
| -batch \ |
| -startdate 160102000000Z \ |
| -enddate 260102000000Z \ |
| -extensions ca_cert \ |
| -extfile redundant-ca.cnf \ |
| -in out/F.csr \ |
| -out out/F.pem |
| |
| # Note: The startdate for B-by-F MUST be different than that of B-by-C; to make |
| # B-by-F more preferable, the startdate is chosen to be GREATER (later) than |
| # B-by-C. |
| echo F signs B2 |
| CA_COMMON_NAME="F CA - Multi-root" \ |
| CERTIFICATE=F \ |
| openssl ca \ |
| -config redundant-ca.cnf \ |
| -batch \ |
| -startdate 160105000000Z \ |
| -enddate 260102000000Z \ |
| -extensions ca_cert \ |
| -extfile redundant-ca.cnf \ |
| -in out/B.csr \ |
| -out out/B2.pem |
| |
| echo "Generating leaf CSRs" |
| for i in A |
| do |
| echo "Generating leaf ${i}" |
| openssl req \ |
| -config ee.cnf \ |
| -new \ |
| -key "out/${i}.key" \ |
| -out "out/${i}.csr" |
| done |
| |
| echo "Signing leaves" |
| CA_COMMON_NAME="B CA - Multi-root" \ |
| CERTIFICATE=B \ |
| openssl ca \ |
| -config redundant-ca.cnf \ |
| -batch \ |
| -days 3650 \ |
| -extensions user_cert \ |
| -extfile redundant-ca.cnf \ |
| -in out/A.csr \ |
| -out out/A.pem |
| |
| echo "Copying outputs" |
| /bin/sh -c "cat out/A.key out/A.pem > ../certificates/multi-root-A-by-B.pem" |
| /bin/sh -c "cat out/A.pem out/B.pem out/C.pem out/D.pem \ |
| > ../certificates/multi-root-chain1.pem" |
| /bin/sh -c "cat out/A.pem out/B.pem out/C2.pem out/E.pem \ |
| > ../certificates/multi-root-chain2.pem" |
| cp out/B.pem ../certificates/multi-root-B-by-C.pem |
| cp out/B2.pem ../certificates/multi-root-B-by-F.pem |
| cp out/C.pem ../certificates/multi-root-C-by-D.pem |
| cp out/C2.pem ../certificates/multi-root-C-by-E.pem |
| cp out/F.pem ../certificates/multi-root-F-by-E.pem |
| cp out/D.pem ../certificates/multi-root-D-by-D.pem |
| cp out/E.pem ../certificates/multi-root-E-by-E.pem |
| |
| echo "Generating CRLSets" |
| # Block D and E by SPKI; invalidates all paths. |
| python crlsetutil.py -o ../certificates/multi-root-crlset-D-and-E.raw \ |
| <<CRLSETDOCBLOCK |
| { |
| "BlockedBySPKI": [ |
| "out/D.pem", |
| "out/E.pem" |
| ] |
| } |
| CRLSETDOCBLOCK |
| |
| # Block E by SPKI. |
| python crlsetutil.py -o ../certificates/multi-root-crlset-E.raw \ |
| <<CRLSETDOCBLOCK |
| { |
| "BlockedBySPKI": [ |
| "out/E.pem" |
| ] |
| } |
| CRLSETDOCBLOCK |
| |
| # Block C-by-D and F-by-E by way of serial number. |
| python crlsetutil.py -o ../certificates/multi-root-crlset-CD-and-FE.raw \ |
| <<CRLSETDOCBLOCK |
| { |
| "BlockedByHash": { |
| "out/D.pem": ["out/C.pem"], |
| "out/E.pem": ["out/F.pem"] |
| } |
| } |
| CRLSETDOCBLOCK |
| |
| # Block C (all versions) by way of SPKI |
| python crlsetutil.py -o ../certificates/multi-root-crlset-C.raw \ |
| <<CRLSETDOCBLOCK |
| { |
| "BlockedBySPKI": [ "out/C.pem" ] |
| } |
| CRLSETDOCBLOCK |
| |
| # Block an unrelated/unissued serial (D, not issued by E) to enable all paths. |
| python crlsetutil.py -o ../certificates/multi-root-crlset-unrelated.raw \ |
| <<CRLSETDOCBLOCK |
| { |
| "BlockedByHash": { |
| "out/E.pem": ["out/D.pem"] |
| } |
| } |
| CRLSETDOCBLOCK |