blob: 845176eca937292607eacddded2ebe3948d7405a [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001#!/usr/bin/make -s
2#
3# This file is inspired from freeDiameter's contrib/ca_script and
4# improved to handle multiple CA in a hierarchical fashion.
5# Warning: the directory structure is flat, does not reflect the CA hierarchy
6
7SCRIPT_DIR = .
8DATA_DIR = ./ca_data
9
10CONFIG = -config $(SCRIPT_DIR)/openssl.cnf
11REMAKE = $(MAKE) -f $(SCRIPT_DIR)/Makefile
12
13#Disable "make destroy" -- overwrite on command line
14force =
15
16#RSA key sizes, can be overwritten on command line
17cakeysize = 2048
18keysize = 1024
19
20# Save current date
21DATE=`date +%Y%m%d-%H%M%S`
22
23# Default: print the help
24all: help
25
26# Help message
27help:
28 @echo "\n\
29Available commands:\n\
30 make init topca=name\n\
31 Creates the initial top-level CA structure\n\
32 make newca name=newcaname ca=parentca\n\
33 Creates a new sub-CA that can be used for certificates later.\n\
34 make newcert name=foo ca=parentca\n\
35 Create private key and csr, then issue the certificate (named foo.*)\n\
36 make p12 name=foo ca=parentca\n\
37 Same as newcert, but additionnaly creates a pkcs12 file to ship client certificate to Windows or Mac\n\
38 make ship name=foo ca=parentca\n\
39 Create an archive with the data for the client (useful for freeDiameter peers)\n\
40 make revoke name=foo ca=parentca\n\
41 Revokes the certificate foo.cert issued by parentca and regenerates the CRL.\n\
42 make gencrl ca=caname\n\
43 Regenerates the CRL of CA caname. Should be run periodically.\n\
44\n\
45";
46
47# Destroy the CA hierarchy completely. Use with care.
48destroy:
49 @if [ -z "$(force)" ]; then echo "Destroy disabled, use: make destroy force=y"; exit 1; fi
50 @if [ ! -d $(SCRIPT_DIR) ]; then echo "Error in setup"; exit 1; fi
51 @echo "Removing everything (for debug purpose)..."
52 @rm -rf $(DATA_DIR)/*
53
54# Initialize the CA structure
55structure:
56 @if [ -z "$(caname)" ]; then echo "Internal error: caname is missing"; exit 1; fi
57 @if [ -d $(DATA_DIR)/$(caname) ]; then echo "CA $(caname) already exists."; exit 1; fi
58 # Creating CA structure
59 @mkdir -p $(DATA_DIR)/$(caname)
60 @mkdir $(DATA_DIR)/$(caname)/public
61 @mkdir $(DATA_DIR)/$(caname)/public/crl
62 @mkdir $(DATA_DIR)/$(caname)/private
63 @chmod 700 $(DATA_DIR)/$(caname)/private
64 @mkdir $(DATA_DIR)/$(caname)/clients
65 @echo "01" > $(DATA_DIR)/$(caname)/serial
66 @echo "01" > $(DATA_DIR)/$(caname)/crlnumber
67 @touch $(DATA_DIR)/$(caname)/index.txt
68
69# Initialize the top-level CA structure and keys.
70init:
71 @if [ -z "$(topca)" ]; then echo "Please specify the name of the root CA. Ex: make init topca=rootca.testbed.aaa"; exit 1; fi
72 # Create the folder hierarchy
73 @$(REMAKE) structure caname=$(topca)
74 # Generate the self-signed certificate
75 @CA_ROOT_DIR=$(DATA_DIR)/$(topca) openssl req $(CONFIG) -new -batch -x509 -days 3650 -nodes -newkey rsa:$(cakeysize) -out $(DATA_DIR)/$(topca)/public/cacert.pem \
76 -keyout $(DATA_DIR)/$(topca)/private/cakey.pem -extensions ca_cert -subj /CN=$(topca)
77 @ln -s cacert.pem $(DATA_DIR)/$(topca)/public/`openssl x509 -noout -hash < $(DATA_DIR)/$(topca)/public/cacert.pem`.0
78 @touch $(DATA_DIR)/$(topca)/public/cachain.pem
79 @ln -s ../../$(topca)/public/cacert.pem $(DATA_DIR)/$(topca)/public/caroot.pem
80 @$(REMAKE) gencrl ca=$(topca)
81
82# Create a secondary CA
83newca:
84 @if [ -z "$(name)" -o -z "$(ca)" ]; then echo "Missing parameter. Ex: make newca name=subca.testbed.aaa ca=rootca.testbed.aaa"; exit 1; fi
85 @if [ ! -e $(DATA_DIR)/$(ca)/private/cakey.pem ]; then echo "The parent CA $(ca) does not exist."; exit 1; fi
86 @if [ ! -d $(DATA_DIR)/$(name) ]; then $(REMAKE) structure caname=$(name); fi
87 # Generate the private key and CSR for the new CA if needed
88 @if [ ! -e $(DATA_DIR)/$(name)/private/cakey.pem ]; then \
89 openssl genrsa -out $(DATA_DIR)/$(name)/private/cakey.pem $(cakeysize) ; fi
90 @if [ ! -e $(DATA_DIR)/$(name)/private/cacsr.pem ]; then \
91 CA_ROOT_DIR=$(DATA_DIR)/$(name) openssl req $(CONFIG) -new -batch -out $(DATA_DIR)/$(name)/private/cacsr.pem \
92 -key $(DATA_DIR)/$(name)/private/cakey.pem \
93 -subj /CN=$(name) -reqexts v3_req_ca; fi
94 # Revoke a previous certificate for this CA if any
95 @if [ -e $(DATA_DIR)/$(name)/public/cacert.pem ]; then \
96 echo "Revoking previous certificate ..."; \
97 $(REMAKE) revoke name=$(name) ca=$(ca); \
98 mv $(DATA_DIR)/$(name)/public/cacert.pem $(DATA_DIR)/$(name)/public/cacert-$(DATE).pem; fi
99 # Issue the new CA certificate
100 @CA_ROOT_DIR=$(DATA_DIR)/$(ca) openssl ca $(CONFIG) -in $(DATA_DIR)/$(name)/private/cacsr.pem \
101 -out $(DATA_DIR)/$(name)/public/cacert.pem \
102 -batch -extensions ca_cert
103 # Hash and link to parent
104 @ln -s cacert.pem $(DATA_DIR)/$(ca)/public/`openssl x509 -noout -hash < $(DATA_DIR)/$(name)/public/cacert.pem`.0
105 @rm -f $(DATA_DIR)/$(name)/parent
106 @ln -s ../$(ca) $(DATA_DIR)/$(name)/parent
107 @cat $(DATA_DIR)/$(name)/public/cacert.pem $(DATA_DIR)/$(ca)/public/cachain.pem > $(DATA_DIR)/$(name)/public/cachain.pem
108 @ln -s ../../$(ca)/public/caroot.pem $(DATA_DIR)/$(name)/public/caroot.pem
109 @for CRLFILE in `cd $(DATA_DIR)/$(ca)/public/crl && ls -1`; do ln -sf ../../../$(ca)/public/crl/$$CRLFILE $(DATA_DIR)/$(name)/public/crl/$$CRLFILE; done
110 @$(REMAKE) gencrl ca=$(name)
111
112# Create a new certificate for use in TLS communications and other terminal usages
113newcert:
114 @if [ -z "$(name)" -o -z "$(ca)" ]; then echo "Missing parameter. Ex: make newcert name=service.testbed.aaa ca=ca.testbed.aaa"; exit 1; fi
115 @if [ ! -e $(DATA_DIR)/$(ca)/private/cakey.pem ]; then echo "The parent CA $(ca) does not exist."; exit 1; fi
116 @if [ ! -d $(DATA_DIR)/$(ca)/clients/$(name) ]; then mkdir $(DATA_DIR)/$(ca)/clients/$(name); fi
117 # Create a private key if needed
118 @if [ ! -e $(DATA_DIR)/$(ca)/clients/$(name)/privkey.pem ]; then \
119 openssl genrsa -out $(DATA_DIR)/$(ca)/clients/$(name)/privkey.pem $(keysize); fi
120 # Create a CSR if needed
121 @if [ ! -e $(DATA_DIR)/$(ca)/clients/$(name)/csr.pem ]; then \
122 CA_ROOT_DIR=$(DATA_DIR)/$(ca) openssl req $(CONFIG) -new -batch -out $(DATA_DIR)/$(ca)/clients/$(name)/csr.pem \
123 -key $(DATA_DIR)/$(ca)/clients/$(name)/privkey.pem \
124 -subj /CN=$(name); fi
125 # Revoke a previous certificate if any
126 @if [ -e $(DATA_DIR)/$(ca)/clients/$(name)/cert.pem ]; then \
127 $(REMAKE) revoke name=$(name) ca=$(ca); \
128 mv $(DATA_DIR)/$(ca)/clients/$(name)/cert.pem $(DATA_DIR)/$(ca)/clients/$(name)/cert-$(DATE).pem; fi
129 # Now sign the new certificate with the CA key
130 @CA_ROOT_DIR=$(DATA_DIR)/$(ca) openssl ca $(CONFIG) -in $(DATA_DIR)/$(ca)/clients/$(name)/csr.pem \
131 -out $(DATA_DIR)/$(ca)/clients/$(name)/cert.pem \
132 -batch
133 # Hash
134 @ln -sf `cat $(DATA_DIR)/$(ca)/serial.old`.pem $(DATA_DIR)/$(ca)/public/`openssl x509 -noout -hash < $(DATA_DIR)/$(ca)/clients/$(name)/cert.pem`.0
135 # Compiled informations for the client
136 @cat $(DATA_DIR)/$(ca)/clients/$(name)/cert.pem $(DATA_DIR)/$(ca)/public/cachain.pem > $(DATA_DIR)/$(ca)/clients/$(name)/certchain.pem
137 @ln -sf ../../public/crl $(DATA_DIR)/$(ca)/clients/$(name)/crl
138 @ln -sf ../../public/caroot.pem $(DATA_DIR)/$(ca)/clients/$(name)/ca.pem
139
140# Create a PKCS#12 file containing the client's information
141p12: newcert
142 # Create the PKCS#12 file
143 @cat $(DATA_DIR)/$(ca)/clients/$(name)/privkey.pem \
144 $(DATA_DIR)/$(ca)/clients/$(name)/certchain.pem \
145 $(DATA_DIR)/$(ca)/clients/$(name)/ca.pem \
146 | openssl pkcs12 -export -out $(DATA_DIR)/$(ca)/clients/$(name)/$(name).p12
147 @echo "Client certificate is created in $(DATA_DIR)/$(ca)/clients/$(name)/$(name).p12"
148
149# Create an archive to send the data to the client node
150ship:
151 @if [ -z "$(name)" -o -z "$(ca)" ]; then echo "Missing parameter. Ex: make ship name=service.testbed.aaa ca=ca.testbed.aaa"; exit 1; fi
152 @if [ ! -e $(DATA_DIR)/$(ca)/private/cakey.pem ]; then echo "The parent CA $(ca) does not exist."; exit 1; fi
153 @if [ ! -e $(DATA_DIR)/$(ca)/clients/$(name)/privkey.pem ]; then echo "The client $(name) does not exist, use 'make newcert' first."; exit 1; fi
154 # Ship the data
155 @tar -c -C $(DATA_DIR)/$(ca)/clients/$(name) -z -f $(ca)_$(name).tar.gz -h .
156 @echo "The files have been packaged into archive: $(ca)_$(name).tar.gz"
157
158# Revoke a certificate
159revoke:
160 @if [ -z "$(name)" -o -z "$(ca)" ]; then echo "Missing parameter. Ex: make revoke name=service.testbed.aaa ca=ca.testbed.aaa"; exit 1; fi
161 @if [ ! -e $(DATA_DIR)/$(ca)/private/cakey.pem ]; then echo "The parent CA $(ca) does not exist."; exit 1; fi
162 @if [ ! -e $(DATA_DIR)/$(ca)/clients/$(name)/cert.pem ]; \
163 then echo "$(DATA_DIR)/$(ca)/clients/$(name)/cert.pem not found"; \
164 exit 1; \
165 fi;
166 # Revoke the certificate
167 @CA_ROOT_DIR=$(DATA_DIR)/$(ca) openssl ca $(CONFIG) -revoke $(DATA_DIR)/$(ca)/clients/$(name)/cert.pem;
168 @$(REMAKE) gencrl ca=$(ca)
169
170# Regenerate the Certificate Revocation List.
171gencrl:
172 @if [ -z "$(ca)" ]; then echo "Missing parameter. Ex: make gencrl ca=ca.testbed.aaa"; exit 1; fi
173 # Create the CRL
174 @CA_ROOT_DIR=$(DATA_DIR)/$(ca) openssl ca $(CONFIG) -gencrl -out $(DATA_DIR)/$(ca)/public/crl/$(ca).pem
175 @ln -s crl/$(ca).pem $(DATA_DIR)/$(ca)/public/local.pem
176 @ln -s local.pem $(DATA_DIR)/$(ca)/public/`openssl crl -noout -hash < $(DATA_DIR)/$(ca)/public/crl/$(ca).pem`.r0
177
178# End of file...