mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +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,19 +508,44 @@ 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) | ||||||
|  | 		if err != nil { | ||||||
|  | 			clientExtMap[ext.Id.String()] = "" | ||||||
|  | 		} else { | ||||||
| 			clientExtMap[ext.Id.String()] = parsedValue | 			clientExtMap[ext.Id.String()] = parsedValue | ||||||
| 		} | 		} | ||||||
| 	// If any of the required extensions don'log match the constraint fails |  | ||||||
|  | 		hexExtMap[ext.Id.String()] = hex.EncodeToString(ext.Value) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// 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) | ||||||
|  | 		if len(reqExt) != 2 { | ||||||
|  | 			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]] | 			clientExtValue, clientExtValueOk := clientExtMap[reqExt[0]] | ||||||
| 			if !clientExtValueOk || !glob.Glob(reqExt[1], clientExtValue) { | 			if !clientExtValueOk || !glob.Glob(reqExt[1], clientExtValue) { | ||||||
| 				return false | 				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
	 Rachel Culpepper
					Rachel Culpepper