| #!/bin/bash |
| # Copyright 2016 The LUCI Authors. All rights reserved. |
| # Use of this source code is governed under the Apache License, Version 2.0 |
| # that can be found in the LICENSE file. |
| |
| # includes.sh is included by all other scripts. |
| # |
| # It contains a bunch of global variables and functions. |
| |
| |
| # Change to your Cloud Project ID. See README.md. |
| CLOUD_PROJECT_ID=my-cloud-project |
| |
| |
| WORKING_DIR=/tmp/token_server_test |
| CA_DIR=$WORKING_DIR/ca |
| CA_NAME="Fake CA: fake.ca" |
| |
| mkdir -p "$WORKING_DIR" |
| |
| DEVSERVER_PORT=8080 |
| DEVSERVER_ADMIN_PORT=8100 |
| CRLSERVER_PORT=8200 |
| |
| DEVCFG_PATH=`dirname $PWD`/appengine/devcfg/services/$CLOUD_PROJECT_ID |
| |
| |
| # initialize_ca builds a new simple self-signed CA. |
| # |
| # See https://jamielinux.com/docs/openssl-certificate-authority/ |
| function initialize_ca { |
| rm -rf "$CA_DIR" |
| |
| mkdir "$CA_DIR" |
| mkdir "$CA_DIR/certs" |
| mkdir "$CA_DIR/crl" |
| mkdir "$CA_DIR/csr" |
| mkdir "$CA_DIR/newcerts" |
| mkdir "$CA_DIR/private" |
| |
| touch "$CA_DIR/index.txt" |
| echo 1000 > "$CA_DIR/serial" |
| echo 1000 > "$CA_DIR/crlnumber" |
| |
| cat > "$CA_DIR/openssl.cnf" <<EOL |
| [ca] |
| default_ca = CA_default |
| |
| [CA_default] |
| dir = $CA_DIR |
| certs = $CA_DIR/certs |
| crl_dir = $CA_DIR/crl |
| new_certs_dir = $CA_DIR/newcerts |
| database = $CA_DIR/index.txt |
| serial = $CA_DIR/serial |
| RANDFILE = $CA_DIR/private/.rand |
| |
| # The root key and root certificate. |
| private_key = $CA_DIR/private/ca.pem |
| certificate = $CA_DIR/certs/ca.pem |
| |
| # For certificate revocation lists. |
| crlnumber = $CA_DIR/crlnumber |
| crl = $CA_DIR/crl/crl.pem |
| crl_extensions = crl_ext |
| default_crl_days = 30 |
| |
| default_md = sha256 |
| name_opt = ca_default |
| cert_opt = ca_default |
| default_days = 375 |
| preserve = no |
| policy = policy_loose |
| |
| [policy_loose] |
| countryName = optional |
| stateOrProvinceName = optional |
| localityName = optional |
| organizationName = optional |
| organizationalUnitName = optional |
| commonName = supplied |
| emailAddress = optional |
| |
| [req] |
| default_bits = 2048 |
| distinguished_name = req_distinguished_name |
| string_mask = utf8only |
| default_md = sha256 |
| x509_extensions = v3_ca |
| |
| [req_distinguished_name] |
| countryName = Country Name (2 letter code) |
| stateOrProvinceName = State or Province Name |
| localityName = Locality Name |
| 0.organizationName = Organization Name |
| organizationalUnitName = Organizational Unit Name |
| commonName = Common Name |
| emailAddress = Email Address |
| |
| [v3_ca] |
| subjectKeyIdentifier = hash |
| authorityKeyIdentifier = keyid:always,issuer |
| basicConstraints = critical, CA:true |
| keyUsage = critical, digitalSignature, cRLSign, keyCertSign |
| |
| [client_cert] |
| basicConstraints = CA:FALSE |
| nsCertType = client, email |
| nsComment = "OpenSSL Generated Client Certificate" |
| subjectKeyIdentifier = hash |
| authorityKeyIdentifier = keyid,issuer |
| keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment |
| extendedKeyUsage = clientAuth, emailProtection |
| |
| [crl_ext] |
| authorityKeyIdentifier=keyid:always |
| EOL |
| |
| # Create the root key pair. |
| openssl genrsa -out "$CA_DIR/private/ca.pem" 2048 |
| |
| # Create the root (self-signed) certificate. |
| openssl req -config "$CA_DIR/openssl.cnf" \ |
| -key "$CA_DIR/private/ca.pem" \ |
| -new -x509 -days 7300 -sha256 -extensions v3_ca \ |
| -out "$CA_DIR/certs/ca.pem" \ |
| -subj "/C=US/ST=California/L=Blah/O=Stuff Inc/CN=$CA_NAME" |
| |
| # Generate first CRL. |
| regen_crl |
| } |
| |
| |
| # create_client_certificate creates a new client key pair and signs the cert. |
| # |
| # Uses CA initialized with initialize_ca. |
| function create_client_certificate { |
| local name=$1 |
| |
| # Generate a key pair. |
| openssl genrsa -out "$CA_DIR/private/$name.pem" 2048 |
| |
| # Generate a certificate signing request. |
| openssl req -config "$CA_DIR/openssl.cnf" \ |
| -key "$CA_DIR/private/$name.pem" \ |
| -new -sha256 -out "$CA_DIR/csr/$name.pem" \ |
| -subj "/C=US/ST=California/L=Blah/O=Stuff Inc/CN=$name" |
| |
| # Ask CA to sign the certificate. |
| openssl ca -batch -config "$CA_DIR/openssl.cnf" \ |
| -extensions client_cert -days 375 -notext -md sha256 \ |
| -in "$CA_DIR/csr/$name.pem" \ |
| -out "$CA_DIR/certs/$name.pem" |
| |
| regen_crl |
| } |
| |
| # revoke_client_certificate revokes previously issued certificate. |
| # |
| # Uses CA initialized with initialize_ca. |
| function revoke_client_certificate { |
| local name=$1 |
| |
| openssl ca -config "$CA_DIR/openssl.cnf" -revoke "$CA_DIR/certs/$name.pem" |
| regen_crl |
| } |
| |
| |
| # regen_crl regenerates certificate revocation list file. |
| function regen_crl { |
| openssl ca -config "$CA_DIR/openssl.cnf" -gencrl -out "$CA_DIR/crl/crl.pem" |
| openssl crl -outform der -in "$CA_DIR/crl/crl.pem" -out "$CA_DIR/crl/crl.der" |
| } |
| |
| |
| # call_rpc invokes pRPC method on devserver instance. |
| # |
| # It reads method body as JSON from stdin. |
| function call_rpc { |
| echo "Calling $1..." |
| rpc call -format json "localhost:$DEVSERVER_PORT" $1 |
| if [ $? -ne 0 ] |
| then |
| echo "RPC call $1 failed!" |
| exit 1 |
| fi |
| } |
| |
| |
| # import_config imports CA config into the token server. |
| function import_config { |
| mkdir -p $DEVCFG_PATH/certs |
| cp $CA_DIR/certs/ca.pem $DEVCFG_PATH/certs/ca.pem |
| |
| cat >$DEVCFG_PATH/tokenserver.cfg <<EOL |
| certificate_authority { |
| cn: "$CA_NAME" |
| cert_path: "certs/ca.pem" |
| crl_url: "http://localhost:$CRLSERVER_PORT/ca/crl/crl.der" |
| use_oauth: false |
| |
| known_domains: { |
| domain: "fake.domain" |
| machine_token_lifetime: 3600 |
| } |
| } |
| EOL |
| |
| # Ask the server to reread the config. |
| echo "{}" | call_rpc "tokenserver.admin.Admin.ImportCAConfigs" |
| |
| # Wait a bit for cached config to expire. |
| sleep 0.5 |
| } |
| |
| |
| # fetch_crl imports current CRL into the token server. |
| function fetch_crl { |
| call_rpc "tokenserver.admin.CertificateAuthorities.FetchCRL" <<EOL |
| { |
| "cn": "$CA_NAME", |
| "force": true |
| } |
| EOL |
| } |