topdown: Add built-in HMAC compare function

Add crypto.hmac.equal built-in function to safelly comparing hashes generated by MD5, SHA-1, SHA-256 and SHA-512 hashing algorithms.

The built-in function is a wrapped for the function Equal of package crypto/hmac.

It's useful when you need to write a policy that requires to check hash signature for request body.

Signed-off-by: Sandokan D. Arantes <sandokandias@gmail.com>
This commit is contained in:
Sandokan D. Arantes
2023-04-20 22:05:34 -03:00
committed by Ashutosh Narkar
parent 6a1af0fdeb
commit 1731907295
5 changed files with 141 additions and 0 deletions
+13
View File
@@ -214,6 +214,7 @@ var DefaultBuiltins = [...]*Builtin{
CryptoHmacSha1,
CryptoHmacSha256,
CryptoHmacSha512,
CryptoHmacEqual,
// Graphs
WalkBuiltin,
@@ -2380,6 +2381,18 @@ var CryptoHmacSha512 = &Builtin{
),
}
var CryptoHmacEqual = &Builtin{
Name: "crypto.hmac.equal",
Description: "Returns a boolean representing the result of comparing two MACs for equality without leaking timing information.",
Decl: types.NewFunction(
types.Args(
types.Named("mac1", types.S).Description("mac1 to compare"),
types.Named("mac2", types.S).Description("mac2 to compare"),
),
types.Named("result", types.B).Description("`true` if the MACs are equals, `false` otherwise"),
),
}
/**
* Graphs.
*/
+26
View File
@@ -33,6 +33,7 @@
"to_number"
],
"crypto": [
"crypto.hmac.equal",
"crypto.hmac.md5",
"crypto.hmac.sha1",
"crypto.hmac.sha256",
@@ -3202,6 +3203,31 @@
},
"wasm": true
},
"crypto.hmac.equal": {
"args": [
{
"description": "mac1 to compare",
"name": "mac1",
"type": "string"
},
{
"description": "mac2 to compare",
"name": "mac2",
"type": "string"
}
],
"available": [
"edge"
],
"description": "Returns a boolean representing the result of comparing two MACs for equality without leaking timing information.",
"introduced": "edge",
"result": {
"description": "`true` if the MACs are equals, `false` otherwise",
"name": "result",
"type": "boolean"
},
"wasm": false
},
"crypto.hmac.md5": {
"args": [
{
+17
View File
@@ -572,6 +572,23 @@
"type": "function"
}
},
{
"name": "crypto.hmac.equal",
"decl": {
"args": [
{
"type": "string"
},
{
"type": "string"
}
],
"result": {
"type": "boolean"
},
"type": "function"
}
},
{
"name": "crypto.hmac.md5",
"decl": {
@@ -0,0 +1,66 @@
cases:
- note: cryptohmacequal/crypto.hmac.equal_md5
query: data.test.p = x
modules:
- |
package test
p[res] {
res := crypto.hmac.equal(input.mac1, input.mac2)
}
input: {"mac1": "31b6db9e5eb4addb42f1a6ca07367adc", "mac2": "31b6db9e5eb4addb42f1a6ca07367adc"}
want_result:
- x:
- true
- note: cryptohmacequal/crypto.hmac.equal_sha1
query: data.test.p = x
modules:
- |
package test
p[res] {
res := crypto.hmac.equal(input.mac1, input.mac2)
}
input: {"mac1": "85d155c55ed286a300bd1cf124de08d87e914f3a", "mac2": "85d155c55ed286a300bd1cf124de08d87e914f3a"}
want_result:
- x:
- true
- note: cryptohmacequal/crypto.hmac.equal_sha256
query: data.test.p = x
modules:
- |
package test
p[res] {
res := crypto.hmac.equal(input.mac1, input.mac2)
}
input: {"mac1": "147933218aaabc0b8b10a2b3a5c34684c8d94341bcf10a4736dc7270f7741851", "mac2": "147933218aaabc0b8b10a2b3a5c34684c8d94341bcf10a4736dc7270f7741851"}
want_result:
- x:
- true
- note: cryptohmacequal/crypto.hmac.equal_sha512
query: data.test.p = x
modules:
- |
package test
p[res] {
res := crypto.hmac.equal(input.mac1, input.mac2)
}
input: {"mac1": "24257d7210582a65c731ec55159c8184cc24c02489453e58587f71f44c23a2d61b4b72154a89d17b2d49448a8452ea066f4fc56a2bcead45c088572ffccdb3d8", "mac2": "24257d7210582a65c731ec55159c8184cc24c02489453e58587f71f44c23a2d61b4b72154a89d17b2d49448a8452ea066f4fc56a2bcead45c088572ffccdb3d8"}
want_result:
- x:
- true
- note: cryptohmacequal/crypto.hmac.equal_false
query: data.test.p = x
modules:
- |
package test
p[res] {
res := crypto.hmac.equal(input.mac1, input.mac2)
}
input: {"mac1": "31b6db9e5eb4addb42f1a6ca07367adc", "mac2": "31b6db9e5eb4addb"}
want_result:
- x:
- false
+19
View File
@@ -249,6 +249,24 @@ func builtinCryptoHmacSha512(_ BuiltinContext, operands []*ast.Term, iter func(*
return hmacHelper(operands, iter, sha512.New)
}
func builtinCryptoHmacEqual(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
a1 := operands[0].Value
mac1, err := builtins.StringOperand(a1, 1)
if err != nil {
return err
}
a2 := operands[1].Value
mac2, err := builtins.StringOperand(a2, 2)
if err != nil {
return err
}
res := hmac.Equal([]byte(mac1), []byte(mac2))
return iter(ast.BooleanTerm(res))
}
func init() {
RegisterBuiltinFunc(ast.CryptoX509ParseCertificates.Name, builtinCryptoX509ParseCertificates)
RegisterBuiltinFunc(ast.CryptoX509ParseAndVerifyCertificates.Name, builtinCryptoX509ParseAndVerifyCertificates)
@@ -261,6 +279,7 @@ func init() {
RegisterBuiltinFunc(ast.CryptoHmacSha1.Name, builtinCryptoHmacSha1)
RegisterBuiltinFunc(ast.CryptoHmacSha256.Name, builtinCryptoHmacSha256)
RegisterBuiltinFunc(ast.CryptoHmacSha512.Name, builtinCryptoHmacSha512)
RegisterBuiltinFunc(ast.CryptoHmacEqual.Name, builtinCryptoHmacEqual)
}
func verifyX509CertificateChain(certs []*x509.Certificate) ([]*x509.Certificate, error) {