hashicorp / vault

A tool for secrets management, encryption as a service, and privileged access management
https://www.vaultproject.io/
Other
31.13k stars 4.21k forks source link

CSR subject is not carried over to issued certificate #17313

Closed phamrak closed 2 years ago

phamrak commented 2 years ago

Describe the bug CSR subject field is not carried over to certificate subject while PKI signing process. By definition in the RF5280 states that certificate Subject field should identify the entity associated with the public key. The only way to know it for the CA is to read it from the CSR Subject and if valid, pass it to the issued certificate. This is not the case for vault PKI.

To Reproduce

  1. Generate CSR
openssl req -nodes -newkey rsa:2048 -keyout example.key -out example.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=IT Department/CN=example.com"
  1. Create json payload for PKI sign
CERTIFICATE=`cat example.csr | sed -z "s/\n/\\\\\n/g"`
JSON_SIGN="{\"csr\" : \"$CERTIFICATE\"}"
echo $JSON_SIGN
  1. Sign the CSR with vault. Set the X-Vault-Token header to valid token and change host/port to valid destination:

    curl -X POST -H "Content-Type: application/json" -H "X-Vault-Request: true" -H "X-Vault-Token: <token>" http://localhost:8200/v1/pki/sign/example-dot-com --data "$JSON_SIGN" | jq -r '.data.certificate' | sed 's/\\n/\n/g' > ./certificate.crt
  2. Show the text of generated certificate

    openssl x509 -in certificate.crt -noout -text

    ab358abdd468c0d44378fc36421c2f9e977f7e45

Expected behavior Expecting that issued certificate contains the Subject RDNs from CSR. The cert_util.go takes just the settings of the PKI role. It's debatable, but PKI role should state which O,OU etc. are valid but CSR should be the one defining them.

Environment:

Additional context Check discussion 44456

cipherboy commented 2 years ago

@phamrak This is a misunderstanding of how RFC 5280 and PKI work.

CAs are free to use what information from the CSR they want. They aren't bound to taking everything from the CSR or wholesale rejecting it; they're free to modify it and manipulate it into a Certificate in any form (and from any subset of values set on the CSR) that they want. This is well-known behavior of other PKI systems like Dogtag and EJBCA (which have complex issuance policy engines that allow overwriting specific attributes, validating provided ones, or even conditional lookups in the case of Dogtag's Java based engine) or even ACME based CAs -- ACME has out-of-band subject identifiers and will discard what is on the CSR in favor of what was specified in the protocol.

Vault's PKI Secrets engine lets the operator (not the cert requester --- as that'd be a security vulnerability!) control the final cert's subject via roles. The CSR's fields are supposed to be translated to request parameters.

There are three relevant parameters on the role:

  • require_cn (bool: true) - If set to false, makes the common_name field optional while generating a certificate.
  • use_csr_common_name (bool: true) - When used with the CSR signing endpoint, the common name in the CSR will be used instead of taken from the JSON data. This does not include any requested SANs in the CSR; use use_csr_sans for that.
  • use_csr_sans (bool: true) - When used with the CSR signing endpoint, the subject alternate names in the CSR will be used instead of taken from the JSON data. This does not include the common name in the CSR; use use_csr_common_name for that.

It might be that your role has set all of these to false (try a vault read pki/roles/example-dot-com), to reject taking the CN and SANs from the cert, and not to require a CN.

The reason why additional Subject attributes are not specified are because these are typically used in permissions systems (e.g., LDAP) and thus consumes a risk: the operator should grant explicit Group/OU/O permissions via the role, rather than taking potentially insecure values from the CSR. If you want, you can view the role exactly as the request above described: the role disallowed all other attributes, so they're not pulled from the CSR. Add them to the role and they'll be set. ;-)

If you want this type of verbatim certificate issuance, you can use sign-verbatim without the role.

For a more comprehensive Subject construction system, see the feature request in #12426. Closing this one in favor of that one, but note the validation model still needs to be defined. At that point, we'll likely add a third parameter, use_csr_rdns and allow operators to control whether RDNs are used wholesale from the CSR or not (validating them against the new RDN-construction policy engine).


FWIW, I am unable to reproduce the above report with the empty subject:

[cipherboy@xps15 14]$ vault read pki/roles/testing 
Key                                   Value
---                                   -----
allow_any_name                        true
allow_bare_domains                    false
allow_glob_domains                    false
allow_ip_sans                         true
allow_localhost                       true
allow_subdomains                      false
allow_token_displayname               false
allow_wildcard_certificates           true
allowed_domains                       []
allowed_domains_template              false
allowed_other_sans                    []
allowed_serial_numbers                []
allowed_uri_sans                      []
allowed_uri_sans_template             false
basic_constraints_valid_for_non_ca    false
client_flag                           true
cn_validations                        [email hostname]
code_signing_flag                     false
country                               []
email_protection_flag                 false
enforce_hostnames                     true
ext_key_usage                         []
ext_key_usage_oids                    []
generate_lease                        false
issuer_ref                            default
key_bits                              2048
key_type                              rsa
key_usage                             [DigitalSignature KeyAgreement KeyEncipherment]
locality                              []
max_ttl                               0s
no_store                              false
not_after                             n/a
not_before_duration                   30s
organization                          []
ou                                    []
policy_identifiers                    []
postal_code                           []
province                              []
require_cn                            true
server_flag                           true
signature_bits                        256
street_address                        []
ttl                                   0s
use_csr_common_name                   true
use_csr_sans                          true
use_pss                               false
[cipherboy@xps15 14]$ openssl req -nodes -newkey rsa:2048 -keyout example.key -out example.csr -subj "/C=GB/ST=London/L=London/O=Global Security/OU=IT Department/CN=example.com"
.............+.............+.....+.......+.........+...+...........+.+...+...+..+.+.....+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+......+..+.......+.....+...+.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*...+......+..+...+...+............+...+....+...+...+..+.......+...+..................+..+..........+...+......+...+..+...+.+......+.........+......+........+................+.....+......+.+..+..........+.....................+.....+.+.........+.....+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.......+..+....+..................+..+...+......+.+......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.+............+...+..+.......+.....+.+..............+...+...+.+...+.....+.......+........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*.........+......+...........+...+...+...................+...+...+...+..+...+.........+.+..+.......+..+..........+...+...+........+.+......+........+.+.........+.........+..+......+...+.+.....+....+..+...+....+.....+..........+.....+...+....+......+...+......+...............+.....+....+......+...+...+..+...+....+.....+.........+.......+..+.+...............+..+...+..........+.....+.+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-----
[cipherboy@xps15 14]$ vault write pki/sign/testing csr=@example.csr ttl=5s
Key              Value
---              -----
ca_chain         [-----BEGIN CERTIFICATE-----
MIIDFTCCAf2gAwIBAgIUU+COV4AAXEufDAcF8sz431hLjKIwDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAxMHUk9PVCBYMTAeFw0yMjA5MjYxNDQyNTJaFw0yMjEwMjgx
NDQzMjJaMBIxEDAOBgNVBAMTB1JPT1QgWDEwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDTothnktgKcdfuzx1TvxwBdciDFmkBerJjPOn1ZKOh+IWVGEHw
gR60Df51idcE8wrCNk42X3wYRs9QbPMMA6GrWNXYf6hlpoRJuCKTKGOHhgJbW8iW
W+FJeYaUepcfgy39JH/VHpRhVMCsYJtq4oGm6cBDCy5vZXLIorkRULE9sDv0N1B6
Xy7xUGSdT5PWoYwe/GMKQzjyb7wi5oXZp9r73/29jH6+mUqVB3SgkFS/bem9zqRS
XKhSI0HMK5bfFq8bajHrUVkA3dmS2FUjMOzgGScZzrW+whcS8VS50zHXtFzbnH7F
yV3KAKBfw1VPLl7QRpzY8Ijb5DtidYyjK3oDAgMBAAGjYzBhMA4GA1UdDwEB/wQE
AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR1c2pymFDFJ5t3TKvsQmxw
AfcUTDAfBgNVHSMEGDAWgBR1c2pymFDFJ5t3TKvsQmxwAfcUTDANBgkqhkiG9w0B
AQsFAAOCAQEAYCHJ4w3GbrMmz+LZKeviECQIZ/NvJzvmNg6zHlmoh1kZUCLaq9iD
mAcRxqlf5Jdck1puXmZaeIAcyEL2FvBNGgIVvkfMrhmh0XqZuT5R42boPS+DwJ4S
jJhmUTR7fK/m+7gjt8ajj4kiL9AGTKXF9XIpgOJ4yxIQnvPXC0SEKEXhBxyITt4b
40XzcOexkj/0jKmpD8520vtRmjyuW2fumMHz6e2Up5IBAKUiYyhrri+Nzpw6eB5a
qxfbi78J5j7k3MDoSXbY6UHM6qkhsqtcqHHFZX+5OaEU23eARCLDOQpuXchXoOSW
WfdRwxapsLbVjaGmNL5U5NzwBaiQbrJRCg==
-----END CERTIFICATE-----]
certificate      -----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgIUJD8rIp12ciO5sgIbMNoZC3UFqaswDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAxMHUk9PVCBYMTAeFw0yMjA5MjYxNDQzMDJaFw0yMjA5MjYx
NDQzMzdaMBYxFDASBgNVBAMTC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAu3R5myHrNZUOda4BqZc7sktrOtRu3J1A1+0WeZfrfpZS
aD2ZbjgDaxcQSMRl3sJCC3fgAEHs2jxjzoLNievD9wRQFyBCNaNKUV5i1W2CrvfV
GH9JWedRng+oCBUog/URTR0sOyBj7q5SePDzXYVfXF2S3ns9EVxLFsBzUEDh18TB
au+qQKeMYNT3YTJkJDTYnUlDP/2XBbxjJPW1wEdrWD/nz6dzq8N4x+GLTIc3LjlR
jmjGYdBmMnVAnyfr1i5hdcPidUlfmTw1317QfYghGq/pSIT0cUnp9XSYR/HWGL/N
sxQyw5QjZdTJlVzWGn2zny2xtJ15nTUNMdXKfwTfBwIDAQABo4GKMIGHMA4GA1Ud
DwEB/wQEAwIDqDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0O
BBYEFACh0qe7CfHhg0FrIY1QndB4Y4kDMB8GA1UdIwQYMBaAFHVzanKYUMUnm3dM
q+xCbHAB9xRMMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUA
A4IBAQA5vjWi2+eXqqgClv6/g4nrQCMUCBXfx/R3xVyBiMhC4kQrFyVjtk4XnLQx
ixWfL21tVA7QmNWYojKZbqUhFuvbDv4tc2qZwTORRADO7ZqBnDvRj3XRxXKkq0vi
Dm+4fNa/h3WUXOU50fQbTEHQPU/TDUdjxl292ozxxs9k5WEF5UDpqng6nJR2znUu
2QmtOe9u7g6wIT0T+/iocr7nhxGbgh2pv9dJPcPFTiP/GRD7+etX7BZIVWk8AvxV
IS3MzV4XEOYrr+2IgtY2Mj9vR//pg1vkHhkJbABouycpQID87siooyl0PqwcE+B4
6IcfGlehaUnIjGbkZ7OF1EDXxpbC
-----END CERTIFICATE-----
expiration       1664203417
issuing_ca       -----BEGIN CERTIFICATE-----
MIIDFTCCAf2gAwIBAgIUU+COV4AAXEufDAcF8sz431hLjKIwDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAxMHUk9PVCBYMTAeFw0yMjA5MjYxNDQyNTJaFw0yMjEwMjgx
NDQzMjJaMBIxEDAOBgNVBAMTB1JPT1QgWDEwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDTothnktgKcdfuzx1TvxwBdciDFmkBerJjPOn1ZKOh+IWVGEHw
gR60Df51idcE8wrCNk42X3wYRs9QbPMMA6GrWNXYf6hlpoRJuCKTKGOHhgJbW8iW
W+FJeYaUepcfgy39JH/VHpRhVMCsYJtq4oGm6cBDCy5vZXLIorkRULE9sDv0N1B6
Xy7xUGSdT5PWoYwe/GMKQzjyb7wi5oXZp9r73/29jH6+mUqVB3SgkFS/bem9zqRS
XKhSI0HMK5bfFq8bajHrUVkA3dmS2FUjMOzgGScZzrW+whcS8VS50zHXtFzbnH7F
yV3KAKBfw1VPLl7QRpzY8Ijb5DtidYyjK3oDAgMBAAGjYzBhMA4GA1UdDwEB/wQE
AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR1c2pymFDFJ5t3TKvsQmxw
AfcUTDAfBgNVHSMEGDAWgBR1c2pymFDFJ5t3TKvsQmxwAfcUTDANBgkqhkiG9w0B
AQsFAAOCAQEAYCHJ4w3GbrMmz+LZKeviECQIZ/NvJzvmNg6zHlmoh1kZUCLaq9iD
mAcRxqlf5Jdck1puXmZaeIAcyEL2FvBNGgIVvkfMrhmh0XqZuT5R42boPS+DwJ4S
jJhmUTR7fK/m+7gjt8ajj4kiL9AGTKXF9XIpgOJ4yxIQnvPXC0SEKEXhBxyITt4b
40XzcOexkj/0jKmpD8520vtRmjyuW2fumMHz6e2Up5IBAKUiYyhrri+Nzpw6eB5a
qxfbi78J5j7k3MDoSXbY6UHM6qkhsqtcqHHFZX+5OaEU23eARCLDOQpuXchXoOSW
WfdRwxapsLbVjaGmNL5U5NzwBaiQbrJRCg==
-----END CERTIFICATE-----
serial_number    24:3f:2b:22:9d:76:72:23:b9:b2:02:1b:30:da:19:0b:75:05:a9:ab

This certificate has example.com on the CN field. When I either remove the CN from the CSR (and leave it off the API call) or modify the role to set use_csr_common_name=false, I get:

[cipherboy@xps15 14]$ vault write pki/sign/testing csr=@example.csr ttl=5s
Error writing data to pki/sign/testing: Error making API request.

URL: PUT http://localhost:8200/v1/pki/sign/testing
Code: 400. Errors:

* the common_name field is required, or must be provided in a CSR with "use_csr_common_name" set to true, unless "require_cn" is set to false

So likely, you're also interacting with a role with require_cn=false.

HTH,

phamrak commented 2 years ago

Thx @cipherboy! I'll keep watching #12426.

Just some sidenotes, may be someone will reach this point once. We're using k8s cert-manager with vault to issue certificates and it allows to specify (check more here):

  subject:
    organizations:
      - jetstack

Found out while digging, that the cert-manager is adding the subject to the CSR and calls a PKI role to sign, but the generated certificate is not having any organization (the PKI role doesn't define any in our case). Agree it's a security concern without validation, but eager to have once the use_csr_rdns option.

cipherboy commented 2 years ago

@phamrak Can you add the organization to the role that cert-manager is hitting? E.g., vault write pki/roles/example-dot-com ... o=jetstack?

I think from my discussions with Ricardo that is how it is typically deployed, with each cert-manager using a different role based on the desired organizations...

phamrak commented 2 years ago

@cipherboy yes, we can split the roles by organizations. My previous post was about that the cert-manager subject configuration is ignored. Understand the reason why it's like this on behind, but it's not obvious. A nice hint about in the documentation would be nice. But not sure where's the best place, probably in cert-manager itself.

Jwy-jump commented 1 year ago

@cipherboy @phamrak

`vault write test/roles/test_server key_bits=2048  max_ttl=8750h  allow_any_name=true require_cn=false use_csr_common_name=true
openssl req -new   -key private.key   -out req1.csr -subj "/C=CN/ST=London/L=London/O=example/OU=Personal/CN=we/emailAddress=aospace@com"
`vault write -format=json test/issue/test_server common_name="example.com" csr=@req1.csr format=pem ttl="8660h" | jq -r '.data.certificate' > certificate.crt`

but the cert certificate has no csr subject informations? `

cipherboy commented 1 year ago

C, ST, L, O, OU are not the common name and thus won't be copied over. use_csr_common_name=true strictly uses the Subject/CN field that you should seen should be copied over... Other than you overriding it explicitly on the CLI with common_name perhaps (drop that and it definitely should be).

If you want to sign CSRs as-is, including O/OU information, right now your best approach is using sign-verbatim, which requires pre-verification of the CSR.

The Hashicorp Vault Discuss forum might be a better place for this discussion, tbh.