test -s "$PASSWORD_STORE_DIR/${cert.passPrefix}/${id}/key.pem.gpg" || {
info " generateKey: $PASSWORD_STORE_DIR/${cert.passPrefix}/${id}/key.pem.gpg"
${pkgs.openssl}/bin/openssl genrsa \
- -out stdout \
-rand /dev/urandom \
${toString cert.keySize} |
${pkgs.pass}/bin/pass insert --multiline "${cert.passPrefix}/${id}/key.pem"
'';
generateCert = id: cert:
''
- info '"${id}"'
+ info '"${id}"'
''
+ generateKey id cert
+ ''
- genCert () {
- info " generateCert: ${openssl.opensslHome}/${id}/cert.self-signed.pem"
- ${pkgs.pass}/bin/pass "${cert.passPrefix}/${id}/key.pem" |
- user= \
- ${pkgs.openssl}/bin/openssl req \
- -batch \
- -new \
- -x509 \
- -utf8 \
- -rand /dev/urandom \
- -config ${cert.opensslConf} \
- -extensions self_signed_extensions \
- -reqexts self_signed_extensions \
- -inform PEM \
- -outform PEM \
- -keyform PEM \
- ${lib.optionalString (cert.days != null) "-days ${toString cert.days}"} \
- -set_serial 0x$(sleep 1; date '+%Y%m%d%H%M%S') \
- -reqopt no_pubkey,no_sigdump \
- -key /dev/stdin \
- -out "${openssl.opensslHome}/${id}/cert.self-signed.pem"
- }
- if test ! -s "${openssl.opensslHome}/${id}/cert.self-signed.pem"
- then genCert
- else
- if test ! "${openssl.opensslHome}/${id}/cert.self-signed.pem" -nt \
- "$PASSWORD_STORE_DIR/${cert.passPrefix}/${id}/key.pem.gpg"
- then genCert
- else
- test ! "''${DEEPCHECK:+set}" || {
- info " generateCert: checking wether key and certificate match"
- key_mod_pub="$(
- ${pkgs.pass}/bin/pass "${cert.passPrefix}/${id}/key.pem" |
- ${pkgs.openssl}/bin/openssl rsa -modulus -noout -in /dev/stdin)"
- crt_mod_pub="$(
- ${pkgs.openssl}/bin/openssl x509 -noout -modulus \
- -in "${openssl.opensslHome}/${id}/cert.self-signed.pem")"
- test "$key_mod_pub" = "$crt_mod_pub" ||
- error "key and certificate do not match"
- }
- fi
- fi
- '';
- error = ''
- error(){
- echo >&2 "openssl-init: ERROR: $*"
- exit 1
- }
- '';
+ genCert () {
+ info " generateCert: ${openssl.opensslHome}/${id}/cert.self-signed.pem"
+ ${pkgs.pass}/bin/pass "${cert.passPrefix}/${id}/key.pem" |
+ user= \
+ ${pkgs.openssl}/bin/openssl req \
+ -batch \
+ -new \
+ -x509 \
+ -utf8 \
+ -rand /dev/urandom \
+ -config ${cert.opensslConf} \
+ -extensions self_signed_extensions \
+ -reqexts self_signed_extensions \
+ -inform PEM \
+ -outform PEM \
+ -keyform PEM \
+ ${lib.optionalString (cert.days != null) "-days ${toString cert.days}"} \
+ -set_serial 0x$(sleep 1; date '+%Y%m%d%H%M%S') \
+ -reqopt no_pubkey,no_sigdump \
+ -key /dev/stdin \
+ -out "${openssl.opensslHome}/${id}/cert.self-signed.pem"
+ }
+ if test ! -s "${openssl.opensslHome}/${id}/cert.self-signed.pem"
+ then genCert
+ else
+ if test ! "${openssl.opensslHome}/${id}/cert.self-signed.pem" -nt \
+ "$PASSWORD_STORE_DIR/${cert.passPrefix}/${id}/key.pem.gpg"
+ then genCert
+ else
+ test ! "''${DEEPCHECK:+set}" || {
+ info " generateCert: checking wether key and certificate match"
+ key_mod_pub="$(
+ ${pkgs.pass}/bin/pass "${cert.passPrefix}/${id}/key.pem" |
+ ${pkgs.openssl}/bin/openssl rsa -modulus -noout -in /dev/stdin)"
+ crt_mod_pub="$(
+ ${pkgs.openssl}/bin/openssl x509 -noout -modulus \
+ -in "${openssl.opensslHome}/${id}/cert.self-signed.pem")"
+ test "$key_mod_pub" = "$crt_mod_pub" ||
+ error "key and certificate do not match"
+ }
+ fi
+ fi
+ '';
info = ''
info(){
echo >&2 "openssl-init: $*"
set -eu
set -o pipefail
${info}
- '' +
- generateCerts openssl.certificates
+ '' +
+ generateCerts openssl.certificates
);
openssl-cert-iter = pkgs.writeScriptBin "openssl-cert-iter" ''
set -eu
'';
in
{
-options.openssl = {
- enable = lib.mkEnableOption "Configuration of X.509 certificates";
- opensslHome = lib.mkOption {
- type = types.path;
- default = "sec/openssl";
- description = ''
- OpenSSL's directory.
- '';
- };
- certificates = lib.mkOption {
- default = {};
- example =
- { "example" = rec {
- passPrefix = "x509";
- host = "example.coop";
- distributionPoint = "http://example.coop/x509";
- domains = [ "example.org" ];
- days = 365;
- keySize = 4096;
- digest = "sha512";
- };
- };
- type = types.attrsOf (types.submodule ({name, ...}:
- let cert = openssl.certificates."${name}"; in
- {
- #config.uid = lib.mkDefault uid;
- options = {
- host = lib.mkOption {
- type = types.nullOr types.str;
- example = "example.coop";
- };
- passPrefix = lib.mkOption {
- type = types.str;
- example = "x509";
- default = "x509";
- };
- distributionPoint = lib.mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "http://example.coop/x509";
- };
- domains = lib.mkOption {
- type = types.listOf types.str;
- example = [ "example.coop" ];
- default = [];
- };
- days = lib.mkOption {
- type = types.int;
- default = 3650;
- example = 3650;
- };
- keySize = lib.mkOption {
- type = types.int;
- default = 4096;
- example = 4096;
- };
- digest = lib.mkOption {
- type = types.str;
- default = "sha512";
- example = "sha512";
- description = "A digest from openssl list --digest-commands";
- };
- opensslConf = lib.mkOption {
- type = types.attrsOf types.lines;
- default = {};
- apply = certConf:
- let confBySection =
- cert.opensslConf_common //
- cert.opensslConf_self-signed //
- cert.opensslConf_auth-signed //
- cert.opensslConf_user-cert //
- certConf
- ; in
- pkgs.writeText "openssl.conf"
- (lib.concatStrings
- (lib.mapAttrsToList
- (sectionHead: sectionBody:
- (if sectionHead == "" then "" else "[ ${sectionHead} ]\n") +
- sectionBody)
- confBySection));
- };
- opensslConf_common = lib.mkOption {
- type = types.attrsOf types.lines;
- default = {
- "" = ''
- RANDFILE = ${openssl.opensslHome}/openssl.rand
- oid_section = extra_oids
- default_md = ${cert.digest}
- '';
- extra_oids = ''
- '';
- req = ''
- prompt = no
- distinguished_name = distinguished_name
- string_mask = pkix
- #x509_extensions = root_extensions
- #req_extensions = extension
- #attributes = req_attributes
- '';
- distinguished_name = ''
- commonName = ${cert.host}
- #countryName =
- #stateOrProvinceName =
- #localityName =
- #"0.organizationName" =
- #organizationalUnitName =
- #businessCategory =
- '';
+ options.openssl = {
+ enable = lib.mkEnableOption "Configuration of X.509 certificates";
+ opensslHome = lib.mkOption {
+ type = types.str;
+ default = "sec/openssl";
+ description = ''
+ OpenSSL's directory.
+ '';
+ };
+ certificates = lib.mkOption {
+ default = { };
+ example =
+ {
+ "example" = rec {
+ passPrefix = "x509";
+ host = "example.coop";
+ distributionPoint = "http://example.coop/x509";
+ domains = [ "example.org" ];
+ days = 365;
+ keySize = 4096;
+ digest = "sha512";
};
};
- opensslConf_self-signed = lib.mkOption {
- type = types.attrsOf types.lines;
- default = {
- self_signed_extensions = ''
- basicConstraints = critical,CA:TRUE,pathlen:0
- keyUsage = keyCertSign,cRLSign,digitalSignature,keyEncipherment
- subjectAltName = ${lib.concatMapStringsSep "," (dom: "DNS:${dom}") cert.domains}
- subjectKeyIdentifier = hash
- issuerAltName = issuer:copy
- authorityKeyIdentifier = keyid:always,issuer:always
- '' + lib.optionalString (cert.distributionPoint != null) ''
- authorityInfoAccess = caIssuers;URI:${cert.distributionPoint}/${cert.host}.cert.pem
- crlDistributionPoints = URI:${cert.distributionPoint}/${cert.host}.crl.self-signed.pem
+ type = types.attrsOf (types.submodule ({ name, ... }:
+ let cert = openssl.certificates."${name}"; in
+ {
+ #config.uid = lib.mkDefault uid;
+ options = {
+ host = lib.mkOption {
+ type = types.nullOr types.str;
+ example = "example.coop";
+ };
+ passPrefix = lib.mkOption {
+ type = types.str;
+ example = "x509";
+ default = "x509";
+ };
+ distributionPoint = lib.mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "http://example.coop/x509";
+ };
+ domains = lib.mkOption {
+ type = types.listOf types.str;
+ example = [ "example.coop" ];
+ default = [ ];
+ };
+ days = lib.mkOption {
+ type = types.int;
+ default = 3650;
+ example = 3650;
+ };
+ keySize = lib.mkOption {
+ type = types.int;
+ default = 4096;
+ example = 4096;
+ };
+ digest = lib.mkOption {
+ type = types.str;
+ default = "sha512";
+ example = "sha512";
+ description = "A digest from openssl list --digest-commands";
+ };
+ opensslConf = lib.mkOption {
+ type = types.attrsOf types.lines;
+ default = { };
+ apply = certConf:
+ let
+ confBySection =
+ cert.opensslConf_common //
+ cert.opensslConf_self-signed //
+ cert.opensslConf_auth-signed //
+ cert.opensslConf_user-cert //
+ certConf
+ ;
+ in
+ pkgs.writeText "openssl.conf"
+ (lib.concatStrings
+ (lib.mapAttrsToList
+ (sectionHead: sectionBody:
+ (if sectionHead == "" then "" else "[ ${sectionHead} ]\n") +
+ sectionBody)
+ confBySection));
+ };
+ opensslConf_common = lib.mkOption {
+ type = types.attrsOf types.lines;
+ default = {
+ "" = ''
+ RANDFILE = ${openssl.opensslHome}/openssl.rand
+ oid_section = extra_oids
+ default_md = ${cert.digest}
+ '';
+ extra_oids = ''
'';
- /*
+ req = ''
+ prompt = no
+ distinguished_name = distinguished_name
+ string_mask = pkix
+ #x509_extensions = root_extensions
+ #req_extensions = extension
+ #attributes = req_attributes
+ '';
+ distinguished_name = ''
+ commonName = ${cert.host}
+ #countryName =
+ #stateOrProvinceName =
+ #localityName =
+ #"0.organizationName" =
+ #organizationalUnitName =
+ #businessCategory =
+ '';
+ };
+ };
+ opensslConf_self-signed = lib.mkOption {
+ type = types.attrsOf types.lines;
+ default = {
+ self_signed_extensions = ''
+ basicConstraints = critical,CA:TRUE,pathlen:0
+ keyUsage = keyCertSign,cRLSign,digitalSignature,keyEncipherment
+ subjectAltName = ${lib.concatMapStringsSep "," (dom: "DNS:${dom}") cert.domains}
+ subjectKeyIdentifier = hash
+ issuerAltName = issuer:copy
+ authorityKeyIdentifier = keyid:always,issuer:always
+ '' + lib.optionalString (cert.distributionPoint != null) ''
+ authorityInfoAccess = caIssuers;URI:${cert.distributionPoint}/${cert.host}.cert.pem
+ crlDistributionPoints = URI:${cert.distributionPoint}/${cert.host}.crl.self-signed.pem
+ '';
+ /*
self_signed_ca = ''
dir = ${openssl.opensslHome}/${name}
private_key = $dir/key.pem
crl = $dir/crl.self-signed.pem
database = $dir/idx.self-signed.txt
'';
- */
- };
- };
- opensslConf_auth-signed = lib.mkOption {
- type = types.attrsOf types.lines;
- default = {
- auth_signed_extensions = ''
- basicConstraints = critical,CA:FALSE
- keyUsage = digitalSignature,keyEncipherment
- subjectAltName = ${lib.concatMapStringsSep "," (dom: "DNS:${dom}") cert.domains}
- subjectKeyIdentifier = hash
- issuerAltName = issuer:copy
- authorityKeyIdentifier = keyid:always,issuer:always
- certificatePolicies = @certificate_policies
- '' + lib.optionalString (cert.distributionPoint != null) ''
- authorityInfoAccess = caIssuers;URI:${cert.distributionPoint}/${cert.host}.cert.pem
- crlDistributionPoints = URI:${cert.distributionPoint}/${cert.host}.crl.pem
- '';
- certificate_policies = lib.optionalString (cert.distributionPoint != null) ''
- policyIdentifier = 1.2.250.1.42
- CPS.1 = https://${cert.distributionPoint}/cps
- '';
- /*
+ */
+ };
+ };
+ opensslConf_auth-signed = lib.mkOption {
+ type = types.attrsOf types.lines;
+ default = {
+ auth_signed_extensions = ''
+ basicConstraints = critical,CA:FALSE
+ keyUsage = digitalSignature,keyEncipherment
+ subjectAltName = ${lib.concatMapStringsSep "," (dom: "DNS:${dom}") cert.domains}
+ subjectKeyIdentifier = hash
+ issuerAltName = issuer:copy
+ authorityKeyIdentifier = keyid:always,issuer:always
+ certificatePolicies = @certificate_policies
+ '' + lib.optionalString (cert.distributionPoint != null) ''
+ authorityInfoAccess = caIssuers;URI:${cert.distributionPoint}/${cert.host}.cert.pem
+ crlDistributionPoints = URI:${cert.distributionPoint}/${cert.host}.crl.pem
+ '';
+ certificate_policies = lib.optionalString (cert.distributionPoint != null) ''
+ policyIdentifier = 1.2.250.1.42
+ CPS.1 = https://${cert.distributionPoint}/cps
+ '';
+ /*
ca = ''
dir = ${openssl.opensslHome}/${name}
private_key = $dir/key.pem
crl = $dir/crl.pem
database = $dir/idx.txt
'';
- */
- };
- };
- opensslConf_user-cert = lib.mkOption {
- type = types.attrsOf types.lines;
- default = {
- user_cert_extensions = ''
- basicConstraints = critical,CA:FALSE,pathlen:0
- keyUsage = digitalSignature,keyEncipherment
- subjectAltName = email:$ENV::user@${cert.host}
- subjectKeyIdentifier = hash
- issuerAltName = issuer:copy
- authorityKeyIdentifier = keyid:always,issuer:always
- '' + lib.optionalString (cert.distributionPoint != null) ''
- authorityInfoAccess = caIssuers;URI:${cert.distributionPoint}/${cert.host}.cert.pem
- '';
- };
- };
+ */
+ };
+ };
+ opensslConf_user-cert = lib.mkOption {
+ type = types.attrsOf types.lines;
+ default = {
+ user_cert_extensions = ''
+ basicConstraints = critical,CA:FALSE,pathlen:0
+ keyUsage = digitalSignature,keyEncipherment
+ subjectAltName = email:$ENV::user@${cert.host}
+ subjectKeyIdentifier = hash
+ issuerAltName = issuer:copy
+ authorityKeyIdentifier = keyid:always,issuer:always
+ '' + lib.optionalString (cert.distributionPoint != null) ''
+ authorityInfoAccess = caIssuers;URI:${cert.distributionPoint}/${cert.host}.cert.pem
+ '';
+ };
+ };
- };
- }));
+ };
+ }));
+ };
};
-};
-config = lib.mkIf openssl.enable {
- nix-shell.buildInputs = [
- openssl-cert-iter
- openssl-cert-print
- openssl-cert-fetch
- openssl-init
- ];
-};
+ config = lib.mkIf openssl.enable {
+ nix-shell.buildInputs = [
+ openssl-cert-iter
+ openssl-cert-print
+ openssl-cert-fetch
+ openssl-init
+ ];
+ };
}