mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
Vault-17911: add support for hex values in oid extension (#21830)
* add support for hex values in oid extension * add changelog * add length check on split and error handling on unmarshal
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
|||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/hashicorp/go-sockaddr"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
@@ -28,8 +29,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-test/deep"
|
"github.com/go-test/deep"
|
||||||
"github.com/hashicorp/go-sockaddr"
|
|
||||||
|
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
|
|
||||||
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
||||||
@@ -1306,6 +1305,12 @@ func TestBackend_ext_singleCert(t *testing.T) {
|
|||||||
testAccStepLoginInvalid(t, connState),
|
testAccStepLoginInvalid(t, connState),
|
||||||
testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false),
|
testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false),
|
||||||
testAccStepLoginInvalid(t, connState),
|
testAccStepLoginInvalid(t, connState),
|
||||||
|
testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "hex:2.5.29.17:*87047F000002*"}, false),
|
||||||
|
testAccStepLoginInvalid(t, connState),
|
||||||
|
testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "hex:2.5.29.17:*87047F000001*"}, false),
|
||||||
|
testAccStepLogin(t, connState),
|
||||||
|
testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.5.29.17:"}, false),
|
||||||
|
testAccStepLogin(t, connState),
|
||||||
testAccStepReadConfig(t, config{EnableIdentityAliasMetadata: false}, connState),
|
testAccStepReadConfig(t, config{EnableIdentityAliasMetadata: false}, connState),
|
||||||
testAccStepCert(t, "web", ca, "foo", allowed{metadata_ext: "2.1.1.1,1.2.3.45"}, false),
|
testAccStepCert(t, "web", ca, "foo", allowed{metadata_ext: "2.1.1.1,1.2.3.45"}, false),
|
||||||
testAccStepLoginWithMetadata(t, connState, "web", map[string]string{"2-1-1-1": "A UTF8String Extension"}, false),
|
testAccStepLoginWithMetadata(t, connState, "web", map[string]string{"2-1-1-1": "A UTF8String Extension"}, false),
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -507,18 +508,43 @@ func (b *backend) matchesCertificateExtensions(clientCert *x509.Certificate, con
|
|||||||
// including its ASN.1 type tag bytes. For the sake of simplicity, assume string type
|
// including its ASN.1 type tag bytes. For the sake of simplicity, assume string type
|
||||||
// and drop the tag bytes. And get the number of bytes from the tag.
|
// and drop the tag bytes. And get the number of bytes from the tag.
|
||||||
clientExtMap := make(map[string]string, len(clientCert.Extensions))
|
clientExtMap := make(map[string]string, len(clientCert.Extensions))
|
||||||
|
hexExtMap := make(map[string]string, len(clientCert.Extensions))
|
||||||
|
|
||||||
for _, ext := range clientCert.Extensions {
|
for _, ext := range clientCert.Extensions {
|
||||||
var parsedValue string
|
var parsedValue string
|
||||||
asn1.Unmarshal(ext.Value, &parsedValue)
|
_, err := asn1.Unmarshal(ext.Value, &parsedValue)
|
||||||
clientExtMap[ext.Id.String()] = parsedValue
|
if err != nil {
|
||||||
|
clientExtMap[ext.Id.String()] = ""
|
||||||
|
} else {
|
||||||
|
clientExtMap[ext.Id.String()] = parsedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
hexExtMap[ext.Id.String()] = hex.EncodeToString(ext.Value)
|
||||||
}
|
}
|
||||||
// If any of the required extensions don'log match the constraint fails
|
|
||||||
|
// If any of the required extensions don't match the constraint fails
|
||||||
for _, requiredExt := range config.Entry.RequiredExtensions {
|
for _, requiredExt := range config.Entry.RequiredExtensions {
|
||||||
reqExt := strings.SplitN(requiredExt, ":", 2)
|
reqExt := strings.SplitN(requiredExt, ":", 2)
|
||||||
clientExtValue, clientExtValueOk := clientExtMap[reqExt[0]]
|
if len(reqExt) != 2 {
|
||||||
if !clientExtValueOk || !glob.Glob(reqExt[1], clientExtValue) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if reqExt[0] == "hex" {
|
||||||
|
reqHexExt := strings.SplitN(reqExt[1], ":", 2)
|
||||||
|
if len(reqHexExt) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
clientExtValue, clientExtValueOk := hexExtMap[reqHexExt[0]]
|
||||||
|
if !clientExtValueOk || !glob.Glob(strings.ToLower(reqHexExt[1]), clientExtValue) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clientExtValue, clientExtValueOk := clientExtMap[reqExt[0]]
|
||||||
|
if !clientExtValueOk || !glob.Glob(reqExt[1], clientExtValue) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
3
changelog/21830.txt
Normal file
3
changelog/21830.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
auth/cert: Adds support for requiring hexadecimal-encoded non-string certificate extension values
|
||||||
|
```
|
||||||
@@ -59,8 +59,9 @@ Sets a CA cert and associated parameters in a role name.
|
|||||||
- `required_extensions` `(string: "" or array: [])` - Require specific Custom
|
- `required_extensions` `(string: "" or array: [])` - Require specific Custom
|
||||||
Extension OIDs to exist and match the pattern. Value is a comma separated
|
Extension OIDs to exist and match the pattern. Value is a comma separated
|
||||||
string or array of `oid:value`. Expects the extension value to be some type
|
string or array of `oid:value`. Expects the extension value to be some type
|
||||||
of ASN1 encoded string. All conditions _must_ be met. Supports globbing on
|
of ASN1 encoded string. All conditions _must_ be met. To match on the hex-encoded
|
||||||
`value`.
|
value of the extension, including non-string extensions, use the format
|
||||||
|
`hex:<oid>:<value>`.Supports globbing on `value`.
|
||||||
- `allowed_metadata_extensions` `(array:[])` - A comma separated string or
|
- `allowed_metadata_extensions` `(array:[])` - A comma separated string or
|
||||||
array of oid extensions. Upon successful authentication, these extensions
|
array of oid extensions. Upon successful authentication, these extensions
|
||||||
will be added as metadata if they are present in the certificate. The
|
will be added as metadata if they are present in the certificate. The
|
||||||
|
|||||||
Reference in New Issue
Block a user