pomerium/pkg/hpke/url.go
Caleb Doxsey ba07afc245
hpke: add HPKE key to JWKS endpoint (#3762)
* hpke: add HPKE key to JWKS endpoint

* fix test, add http caching headers

* fix error message

* use pointers
2022-11-23 08:45:59 -07:00

86 lines
2.3 KiB
Go

package hpke
import (
"fmt"
"net/url"
)
// URL Parameters
const (
ParamSenderPublicKey = "pomerium_hpke_sender_pub"
ParamQuery = "pomerium_hpke_query"
)
// IsEncryptedURL returns true if the url.Values contain an HPKE encrypted query.
func IsEncryptedURL(values url.Values) bool {
return values.Has(ParamSenderPublicKey) && values.Has(ParamQuery)
}
// EncryptURLValues encrypts URL values using the Seal method.
func EncryptURLValues(
senderPrivateKey *PrivateKey,
receiverPublicKey *PublicKey,
values url.Values,
) (encrypted url.Values, err error) {
values = withoutHPKEParams(values)
sealed, err := Seal(senderPrivateKey, receiverPublicKey, []byte(values.Encode()))
if err != nil {
return nil, fmt.Errorf("hpke: failed to seal URL values %w", err)
}
return url.Values{
ParamSenderPublicKey: {senderPrivateKey.PublicKey().String()},
ParamQuery: {encode(sealed)},
}, nil
}
// DecryptURLValues decrypts URL values using the Open method.
func DecryptURLValues(
receiverPrivateKey *PrivateKey,
encrypted url.Values,
) (senderPublicKey *PublicKey, values url.Values, err error) {
if !encrypted.Has(ParamSenderPublicKey) {
return nil, nil, fmt.Errorf("hpke: missing sender public key in query parameters")
}
if !encrypted.Has(ParamQuery) {
return nil, nil, fmt.Errorf("hpke: missing encrypted query in query parameters")
}
senderPublicKey, err = PublicKeyFromString(encrypted.Get(ParamSenderPublicKey))
if err != nil {
return nil, nil, fmt.Errorf("hpke: invalid sender public key parameter: %w", err)
}
sealed, err := decode(encrypted.Get(ParamQuery))
if err != nil {
return nil, nil, fmt.Errorf("hpke: failed decoding query parameter: %w", err)
}
message, err := Open(receiverPrivateKey, senderPublicKey, sealed)
if err != nil {
return nil, nil, fmt.Errorf("hpke: failed to open sealed message: %w", err)
}
decrypted, err := url.ParseQuery(string(message))
if err != nil {
return nil, nil, fmt.Errorf("hpke: invalid query parameter: %w", err)
}
values = withoutHPKEParams(encrypted)
for k, vs := range decrypted {
values[k] = vs
}
return senderPublicKey, values, err
}
func withoutHPKEParams(values url.Values) url.Values {
filtered := make(url.Values)
for k, vs := range values {
if k != ParamSenderPublicKey && k != ParamQuery {
filtered[k] = vs
}
}
return filtered
}