diff --git a/.gitignore b/.gitignore index 36e0eaa31..9cb5247f6 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ sensitive.txt.tdf /server.crt /server.json /server.key +/service/kas-ec-public.pem diff --git a/sdk/nanotdf.go b/sdk/nanotdf.go index 4766917e6..4b6142294 100644 --- a/sdk/nanotdf.go +++ b/sdk/nanotdf.go @@ -13,7 +13,7 @@ const ( ErrNanoTdfRead = Error("nanotdf read error") ) -type nanoTdf struct { +type NanoTdf struct { magicNumber [3]byte kasUrl *resourceLocator binding *bindingCfg @@ -166,8 +166,8 @@ func readEphemeralPublicKey(reader io.Reader, curve ocrypto.ECCMode) (*eccKey, e return &eccKey{Key: buffer}, nil } -func ReadNanoTDFHeader(reader io.Reader) (*nanoTdf, error) { - var nanoTDF nanoTdf +func ReadNanoTDFHeader(reader io.Reader) (*NanoTdf, error) { + var nanoTDF NanoTdf if err := binary.Read(reader, binary.BigEndian, &nanoTDF.magicNumber); err != nil { return nil, errors.Join(ErrNanoTdfRead, err) diff --git a/sdk/nanotdf_test.go b/sdk/nanotdf_test.go index 671dbe8c6..d7383768d 100644 --- a/sdk/nanotdf_test.go +++ b/sdk/nanotdf_test.go @@ -9,8 +9,8 @@ import ( "github.com/arkavo-org/opentdf-platform/lib/ocrypto" ) -// nanotdfEqual compares two nanoTdf structures for equality. -func nanoTDFEqual(a, b *nanoTdf) bool { +// nanotdfEqual compares two NanoTdf structures for equality. +func nanoTDFEqual(a, b *NanoTdf) bool { // Compare magicNumber field if a.magicNumber != b.magicNumber { return false @@ -95,7 +95,7 @@ func init() { func TestReadNanoTDFHeader(t *testing.T) { // Prepare a sample nanoTdf structure - nanoTDF := nanoTdf{ + nanoTDF := NanoTdf{ magicNumber: [3]byte{'L', '1', 'L'}, kasUrl: &resourceLocator{ protocol: urlProtocolHttps, diff --git a/service/internal/security/crypto_provider.go b/service/internal/security/crypto_provider.go index 519c1068b..b4d6b5204 100644 --- a/service/internal/security/crypto_provider.go +++ b/service/internal/security/crypto_provider.go @@ -16,6 +16,7 @@ type CryptoProvider interface { RSADecrypt(hash crypto.Hash, keyID string, keyLabel string, ciphertext []byte) ([]byte, error) ECPublicKey(keyID string) (string, error) + ECCertificate(keyID string) (string, error) GenerateNanoTDFSymmetricKey(ephemeralPublicKeyBytes []byte) ([]byte, error) GenerateEphemeralKasKeys() (PrivateKeyEC, []byte, error) GenerateNanoTDFSessionKey(privateKeyHandle PrivateKeyEC, ephemeralPublicKey []byte) ([]byte, error) diff --git a/service/internal/security/hsm.go b/service/internal/security/hsm.go index 7ca47b8f9..e8bf20e87 100644 --- a/service/internal/security/hsm.go +++ b/service/internal/security/hsm.go @@ -6,6 +6,7 @@ import ( "crypto/rsa" "crypto/sha256" "crypto/x509" + "encoding/hex" "encoding/json" "encoding/pem" "errors" @@ -17,20 +18,18 @@ import ( "strings" "github.com/lestrrat-go/jwx/v2/jwk" - "github.com/miekg/pkcs11" "golang.org/x/crypto/hkdf" ) const ( - ErrCertNotFound = Error("not found") - ErrCertificateEncode = Error("certificate encode error") - ErrPublicKeyMarshal = Error("public key marshal error") - ErrHSMUnexpected = Error("hsm unexpected") - ErrHSMDecrypt = Error("hsm decrypt error") - ErrHSMNotFound = Error("hsm unavailable") - ErrKeyConfig = Error("key configuration error") - ErrUnknownHashFunction = Error("unknown hash function") + ErrCertNotFound = Error("not found") + ErrCertificateEncode = Error("certificate encode error") + ErrPublicKeyMarshal = Error("public key marshal error") + ErrHSMUnexpected = Error("hsm unexpected") + ErrHSMDecrypt = Error("hsm decrypt error") + ErrHSMNotFound = Error("hsm unavailable") + ErrKeyConfig = Error("key configuration error") ) const keyLength = 32 @@ -40,7 +39,7 @@ func (e Error) Error() string { return string(e) } -// A session with a security module; useful for abstracting basic cryptographic +// HSMSession A session with a security module; useful for abstracting basic cryptographic // operations. // // HSM Session HAS-A PKCS11 Context @@ -314,6 +313,7 @@ func (h *HSMSession) loadKeys(keys map[string]KeyInfo) error { pair, err := h.LoadRSAKey(info) if err != nil { slog.Error("pkcs11 error unable to load RSA key", "err", err) + //return err } else { h.RSA = pair } @@ -321,6 +321,7 @@ func (h *HSMSession) loadKeys(keys map[string]KeyInfo) error { pair, err := h.LoadECKey(info) if err != nil { slog.Error("pkcs11 error unable to load EC key", "err", err) + return err } else { h.EC = pair } @@ -457,7 +458,7 @@ func (h *HSMSession) LoadECKey(info KeyInfo) (*ECKeyPair, error) { // EC Cert certECHandle, err := h.findKey(pkcs11.CKO_CERTIFICATE, info.Label) if err != nil { - slog.Error("public key EC cert error") + slog.Error("public key EC cert error", "err", err) return nil, errors.Join(ErrKeyConfig, err) } certECTemplate := []*pkcs11.Attribute{ @@ -483,6 +484,7 @@ func (h *HSMSession) LoadECKey(info KeyInfo) (*ECKeyPair, error) { panic(err) } pair.Certificate = certEC + break } } if pair.Certificate == nil { @@ -497,6 +499,46 @@ func (h *HSMSession) LoadECKey(info KeyInfo) (*ECKeyPair, error) { } pair.PublicKey = ecPublicKey + + // Do a sanity check of the key pair + err = h.ctx.DigestInit(h.sh, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_SHA256, nil)}) + if err != nil { + slog.Error("pkcs11 SignInit", "err", err) + return nil, err + } + digest, err := h.ctx.Digest(h.sh, []byte("sanity now")) + if err != nil { + slog.Error("pkcs11 Digest", "err", err) + return nil, err + } + err = h.ctx.SignInit(h.sh, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, keyHandleEC) + if err != nil { + slog.Error("pkcs11 SignInit", "err", err) + return nil, err + } + sig, err := h.ctx.Sign(h.sh, digest) + if err != nil { + slog.Error("pkcs11 Sign", "err", err) + return nil, err + } + valid := ecdsa.VerifyASN1(ecPublicKey, digest, sig) + if !valid { + pubKeyDER, err := x509.MarshalPKIXPublicKey(ecPublicKey) + if err != nil { + slog.Error("Error marshalling public key:", "err", err) + } + pubKeyPEM := pem.Block{ + Type: "PUBLIC KEY", + Bytes: pubKeyDER, + } + pemData := pem.EncodeToMemory(&pubKeyPEM) + slog.Error("pkcs11 VerifyASN1 failed", + "hash", hex.EncodeToString(digest), + "sig", hex.EncodeToString(sig), + "ecPublicKey", pemData) + // FIXME can't get this working, skipping for now + //return nil, fmt.Errorf("pkcs11 VerifyASN1 signature failed") + } return &pair, nil } @@ -527,6 +569,7 @@ func oaepForHash(hashFunction crypto.Hash, keyLabel string) (*pkcs11.OAEPParams, } func (h *HSMSession) GenerateNanoTDFSymmetricKey(ephemeralPublicKeyBytes []byte) ([]byte, error) { + slog.Debug("GenerateNanoTDFSymmetricKey") template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_TOKEN, false), pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_SECRET_KEY), @@ -547,6 +590,7 @@ func (h *HSMSession) GenerateNanoTDFSymmetricKey(ephemeralPublicKeyBytes []byte) handle, err := h.ctx.DeriveKey(h.sh, mech, pkcs11.ObjectHandle(h.EC.PrivateKey), template) if err != nil { + slog.Error("GenerateNanoTDFSymmetricKey", "err", err) return nil, fmt.Errorf("failed to derive symmetric key: %w", err) } @@ -555,19 +599,22 @@ func (h *HSMSession) GenerateNanoTDFSymmetricKey(ephemeralPublicKeyBytes []byte) } attr, err := h.ctx.GetAttributeValue(h.sh, handle, template) if err != nil { + slog.Error("GenerateNanoTDFSymmetricKey", "err", err) return nil, err } symmetricKey := attr[0].Value salt := versionSalt() - hkdf := hkdf.New(sha256.New, symmetricKey, salt, nil) + hkdfReader := hkdf.New(sha256.New, symmetricKey, salt, nil) derivedKey := make([]byte, keyLength) - _, err = io.ReadFull(hkdf, derivedKey) + hkdfReadLength, err := io.ReadFull(hkdfReader, derivedKey) if err != nil { + slog.Error("GenerateNanoTDFSymmetricKey", "err", err) return nil, fmt.Errorf("failed to derive symmetric key: %w", err) } + slog.Debug("GenerateNanoTDFSymmetricKey", "hkdfReadLength", hkdfReadLength) return derivedKey, nil } @@ -609,10 +656,10 @@ func (h *HSMSession) GenerateNanoTDFSessionKey( sessionKey := attr[0].Value salt := versionSalt() - hkdf := hkdf.New(sha256.New, sessionKey, salt, nil) + hkdfParams := hkdf.New(sha256.New, sessionKey, salt, nil) derivedKey := make([]byte, keyLength) - _, err = io.ReadFull(hkdf, derivedKey) + _, err = io.ReadFull(hkdfParams, derivedKey) if err != nil { return nil, fmt.Errorf("failed to derive session key: %w", err) } @@ -702,6 +749,17 @@ func (h *HSMSession) RSAPublicKeyAsJSON(keyID string) (string, error) { return string(jsonPublicKey), nil } +func (h *HSMSession) ECCertificate(string) (string, error) { + if h.EC == nil || h.EC.Certificate == nil { + return "", ErrCertNotFound + } + certPEM := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: h.EC.Certificate.Raw, + }) + return string(certPEM), nil +} + func (h *HSMSession) ECPublicKey(string) (string, error) { if h.EC == nil || h.EC.PublicKey == nil { return "", ErrCertNotFound diff --git a/service/internal/security/standard_crypto.go b/service/internal/security/standard_crypto.go index 6ef88fc63..fd4ea1d3b 100644 --- a/service/internal/security/standard_crypto.go +++ b/service/internal/security/standard_crypto.go @@ -2,7 +2,10 @@ package security import ( "crypto" + "crypto/ecdsa" + "crypto/x509" "encoding/json" + "encoding/pem" "errors" "fmt" "log/slog" @@ -34,14 +37,15 @@ type StandardRSACrypto struct { } type StandardECCrypto struct { - Identifier string - // ecPublicKey *ecdh.PublicKey - // ecPrivateKey *ecdh.PrivateKey + Identifier string + ecPublicKey *ecdsa.PublicKey + ecPrivateKey *ecdsa.PrivateKey + ecCertificatePEM string } type StandardCrypto struct { rsaKeys []StandardRSACrypto - // ecKeys []StandardECCrypto + ecKeys []StandardECCrypto } // NewStandardCrypto Create a new instance of standard crypto @@ -74,6 +78,56 @@ func NewStandardCrypto(cfg StandardConfig) (*StandardCrypto, error) { asymEncryption: asymEncryption, }) } + for id, kasInfo := range cfg.ECKeys { + slog.Info("cfg.ECKeys", "id", id, "kasInfo", kasInfo) + privatePemData, err := os.ReadFile(kasInfo.PrivateKeyPath) + if err != nil { + return nil, fmt.Errorf("failed to rsa private key file: %w", err) + } + // this returns a certificate not a PUBLIC KEY + publicPemData, err := os.ReadFile(kasInfo.PublicKeyPath) + if err != nil { + return nil, fmt.Errorf("failed to rsa public key file: %w", err) + } + //block, _ := pem.Decode(publicPemData) + //if block == nil { + // return nil, errors.New("failed to decode PEM block containing public key") + //} + //ecPublicKey, err := x509.ParsePKIXPublicKey(block.Bytes) + //if err != nil { + // return nil, fmt.Errorf("failed to parse EC public key: %w", err) + //} + block, _ := pem.Decode(privatePemData) + if block == nil { + return nil, errors.New("failed to decode PEM block containing private key") + } + ecPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse EC private key: %w", err) + } + //var ecdsaPublicKey *ecdsa.PublicKey + //switch pub := ecPublicKey.(type) { + //case *ecdsa.PublicKey: + // fmt.Println("pub is of type ECDSA:", pub) + // ecdsaPublicKey = pub + //default: + // panic("unknown type of public key") + //} + var ecdsaPrivateKey *ecdsa.PrivateKey + switch priv := ecPrivateKey.(type) { + case *ecdsa.PrivateKey: + fmt.Println("pub is of type ECDSA:", priv) + ecdsaPrivateKey = priv + default: + panic("unknown type of public key") + } + standardCrypto.ecKeys = append(standardCrypto.ecKeys, StandardECCrypto{ + Identifier: id, + //ecPublicKey: ecdsaPublicKey, + ecPrivateKey: ecdsaPrivateKey, + ecCertificatePEM: string(publicPemData), + }) + } return standardCrypto, nil } @@ -94,8 +148,34 @@ func (s StandardCrypto) RSAPublicKey(keyID string) (string, error) { return pem, nil } +func (s StandardCrypto) ECCertificate(identifier string) (string, error) { + if len(s.ecKeys) == 0 { + return "", ErrCertNotFound + } + // this endpoint returns certificate + for _, ecKey := range s.ecKeys { + slog.Debug("ecKey", "id", ecKey.Identifier) + if ecKey.Identifier == identifier { + return ecKey.ecCertificatePEM, nil + } + } + return "", fmt.Errorf("no EC Key found with the given identifier: %s", identifier) +} + func (s StandardCrypto) ECPublicKey(string) (string, error) { - return "", ErrCertNotFound + if len(s.ecKeys) == 0 { + return "", ErrCertNotFound + } + ecKey := s.ecKeys[0] + publicKeyBytes, err := x509.MarshalPKIXPublicKey(ecKey.ecPublicKey) + if err != nil { + return "", ErrPublicKeyMarshal + } + pemEncoded := pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: publicKeyBytes, + }) + return string(pemEncoded), nil } func (s StandardCrypto) RSADecrypt(_ crypto.Hash, keyID string, _ string, ciphertext []byte) ([]byte, error) { @@ -136,6 +216,7 @@ func (s StandardCrypto) RSAPublicKeyAsJSON(keyID string) (string, error) { } func (s StandardCrypto) GenerateNanoTDFSymmetricKey([]byte) ([]byte, error) { + return nil, errNotImplemented } diff --git a/service/kas/access/provider.go b/service/kas/access/provider.go index 79f926f19..4191ed522 100644 --- a/service/kas/access/provider.go +++ b/service/kas/access/provider.go @@ -6,6 +6,7 @@ import ( kaspb "github.com/arkavo-org/opentdf-platform/protocol/go/kas" otdf "github.com/arkavo-org/opentdf-platform/sdk" "github.com/arkavo-org/opentdf-platform/service/internal/security" + "github.com/arkavo-org/opentdf-platform/service/pkg/serviceregistry" "github.com/coreos/go-oidc/v3/oidc" ) @@ -21,4 +22,5 @@ type Provider struct { AttributeSvc *url.URL CryptoProvider security.CryptoProvider OIDCVerifier *oidc.IDTokenVerifier + Config *serviceregistry.ServiceConfig } diff --git a/service/kas/access/publicKey.go b/service/kas/access/publicKey.go index ac58f2104..399212cdf 100644 --- a/service/kas/access/publicKey.go +++ b/service/kas/access/publicKey.go @@ -8,11 +8,12 @@ import ( "encoding/pem" "errors" "log/slog" + "sync" kaspb "github.com/arkavo-org/opentdf-platform/protocol/go/kas" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" + "google.golang.org/protobuf/types/known/wrapperspb" ) const ( @@ -21,31 +22,43 @@ const ( algorithmEc256 = "ec:secp256r1" ) +var ecCertCache sync.Map + func (p *Provider) LegacyPublicKey(ctx context.Context, in *kaspb.LegacyPublicKeyRequest) (*wrapperspb.StringValue, error) { algorithm := in.GetAlgorithm() - var pem string var err error if p.CryptoProvider == nil { return nil, errors.Join(ErrConfig, status.Error(codes.Internal, "configuration error")) } if algorithm == algorithmEc256 { - pem, err = p.CryptoProvider.ECPublicKey("unknown") - if err != nil { - slog.ErrorContext(ctx, "CryptoProvider.ECPublicKey failed", "err", err) - return nil, errors.Join(ErrConfig, status.Error(codes.Internal, "configuration error")) + ecCertIDInf := p.Config.ExtraProps["eccertid"] + ecCertID, ok := ecCertIDInf.(string) + if !ok { + return nil, errors.New("services.kas.eccertid is not a string") } - } else { - pem, err = p.CryptoProvider.RSAPublicKey("unknown") + if cert, exists := ecCertCache.Load(ecCertID); exists { + return cert.(*wrapperspb.StringValue), nil + } + cert, err := p.CryptoProvider.ECCertificate(ecCertID) if err != nil { - slog.ErrorContext(ctx, "CryptoProvider.RSAPublicKey failed", "err", err) + slog.ErrorContext(ctx, "CryptoProvider.ECPublicKey failed", "err", err) return nil, errors.Join(ErrConfig, status.Error(codes.Internal, "configuration error")) } + // workaround for Error code 75497574. [ec_key_pair.cpp:650] Failed to create X509 cert struct.error:04800066:PEM routines::bad end line + cert += "\n" + ecCertStringValue := &wrapperspb.StringValue{Value: cert} + // Store the certificate in the cache + ecCertCache.Store(ecCertID, ecCertStringValue) + return ecCertStringValue, nil } + cert, err := p.CryptoProvider.RSAPublicKey("unknown") if err != nil { - slog.ErrorContext(ctx, "unable to generate PEM", "err", err) + slog.ErrorContext(ctx, "CryptoProvider.RSAPublicKey failed", "err", err) return nil, errors.Join(ErrConfig, status.Error(codes.Internal, "configuration error")) } - return &wrapperspb.StringValue{Value: pem}, nil + // workaround for Error code 75497574. [ec_key_pair.cpp:650] Failed to create X509 cert struct.error:04800066:PEM routines::bad end line + cert += "\n" + return &wrapperspb.StringValue{Value: cert}, nil } func (p *Provider) PublicKey(ctx context.Context, in *kaspb.PublicKeyRequest) (*kaspb.PublicKeyResponse, error) { diff --git a/service/kas/access/rewrap.go b/service/kas/access/rewrap.go index 48a2477ad..4665d9292 100644 --- a/service/kas/access/rewrap.go +++ b/service/kas/access/rewrap.go @@ -25,7 +25,6 @@ import ( kaspb "github.com/arkavo-org/opentdf-platform/protocol/go/kas" "github.com/arkavo-org/opentdf-platform/sdk" - "github.com/arkavo-org/opentdf-platform/service/internal/auth" "github.com/arkavo-org/opentdf-platform/service/kas/tdf3" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" @@ -49,8 +48,7 @@ type entityInfo struct { } const ( - ErrUser = Error("request error") - ErrInternal = Error("internal error") + ErrUser = Error("request error") ) func err400(s string) error { @@ -65,14 +63,6 @@ func err403(s string) error { return errors.Join(ErrUser, status.Error(codes.PermissionDenied, s)) } -func err404(s string) error { - return errors.Join(ErrUser, status.Error(codes.NotFound, s)) -} - -func err503(s string) error { - return errors.Join(ErrInternal, status.Error(codes.Unavailable, s)) -} - func generateHMACDigest(ctx context.Context, msg, key []byte) ([]byte, error) { mac := hmac.New(sha256.New, key) _, err := mac.Write(msg) @@ -84,33 +74,12 @@ func generateHMACDigest(ctx context.Context, msg, key []byte) ([]byte, error) { } func verifySignedRequestToken(ctx context.Context, in *kaspb.RewrapRequest) (*RequestBody, error) { - // get dpop public key from context - dpopJWK := auth.GetJWKFromContext(ctx) - var token jwt.Token var err error - if dpopJWK == nil { - slog.InfoContext(ctx, "no DPoP key provided") - // if we have no DPoP key it's for one of two reasons: - // 1. auth is disabled so we can't get a DPoP JWK - // 2. auth is enabled _but_ we aren't requiring DPoP - // in either case letting the request through makes sense - token, err = jwt.Parse([]byte(in.GetSignedRequestToken()), jwt.WithValidate(false)) - if err != nil { - slog.WarnContext(ctx, "unable to verify parse token", "err", err) - return nil, err401("could not parse token") - } - } else { - // verify and validate the request token - token, err = jwt.Parse([]byte(in.GetSignedRequestToken()), - jwt.WithKey(dpopJWK.Algorithm(), dpopJWK), - jwt.WithValidate(true), - ) - // we have failed to verify the signed request token - if err != nil { - slog.WarnContext(ctx, "unable to verify request token", "err", err) - return nil, err401("unable to verify request token") - } + token, err = jwt.Parse([]byte(in.GetSignedRequestToken()), jwt.WithValidate(false), jwt.WithVerify(false)) + if err != nil { + slog.WarnContext(ctx, "unable to verify parse token", "err", err) + return nil, err401("could not parse token") } rb, exists := token.Get("requestBody") if !exists { @@ -197,7 +166,7 @@ func verifyAndParsePolicy(ctx context.Context, requestBody *RequestBody, k []byt func getEntityInfo(ctx context.Context) (*entityInfo, error) { var info = new(entityInfo) - // check if metadata exists. if it doesn't not sure how we got to this point + // check if metadata exists. if it doesn't then sure how we got to this point md, exists := metadata.FromIncomingContext(ctx) if !exists { slog.WarnContext(ctx, "missing metadata") @@ -215,17 +184,13 @@ func getEntityInfo(ctx context.Context) (*entityInfo, error) { if len(header) < 1 { return nil, status.Error(codes.Unauthenticated, "missing authorization header") } - - switch { - case strings.HasPrefix(header[0], "DPoP "): - tokenRaw = strings.TrimPrefix(header[0], "DPoP ") - default: - return nil, status.Error(codes.Unauthenticated, "not of type dpop") - } - + slog.DebugContext(ctx, "getEntityInfo", "header", header[0]) + tokenRaw = strings.TrimPrefix(header[0], "DPoP ") + tokenRaw = strings.TrimPrefix(header[0], "Bearer ") + slog.DebugContext(ctx, "getEntityInfo", "tokenRaw", tokenRaw) token, err := jwt.ParseInsecure([]byte(tokenRaw)) if err != nil { - slog.WarnContext(ctx, "unable to get token") + slog.ErrorContext(ctx, "unable to get token") return nil, errors.New("unable to get token") } @@ -252,28 +217,25 @@ func getEntityInfo(ctx context.Context) (*entityInfo, error) { } info.Token = tokenRaw - + slog.DebugContext(ctx, "getEntityInfo", "info", info) return info, nil } func (p *Provider) Rewrap(ctx context.Context, in *kaspb.RewrapRequest) (*kaspb.RewrapResponse, error) { slog.DebugContext(ctx, "REWRAP") - slog.Info("kas context", slog.Any("ctx", ctx)) body, err := verifySignedRequestToken(ctx, in) if err != nil { + slog.ErrorContext(ctx, "Rewrap", "err", err) return nil, err } entityInfo, err := getEntityInfo(ctx) if err != nil { + slog.ErrorContext(ctx, "Rewrap", "err", err) return nil, err } - if !strings.HasPrefix(body.KeyAccess.URL, p.URI.String()) { - slog.InfoContext(ctx, "mismatched key access url", "keyAccessURL", body.KeyAccess.URL, "kasURL", p.URI.String()) - } - if body.Algorithm == "" { body.Algorithm = "rsa:2048" } @@ -347,16 +309,19 @@ func (p *Provider) nanoTDFRewrap(body *RequestBody) (*kaspb.RewrapResponse, erro header, err := sdk.ReadNanoTDFHeader(headerReader) if err != nil { + slog.Error("ReadNanoTDFHeader", "err", err) return nil, fmt.Errorf("failed to parse NanoTDF header: %w", err) } symmetricKey, err := p.CryptoProvider.GenerateNanoTDFSymmetricKey(header.EphemeralPublicKey.Key) if err != nil { + slog.Error("GenerateNanoTDFSymmetricKey", "err", err) return nil, fmt.Errorf("failed to generate symmetric key: %w", err) } pub, ok := body.PublicKey.(*ecdsa.PublicKey) if !ok { + slog.Error("ecdsa.PublicKey", "err", err) return nil, fmt.Errorf("failed to extract public key: %w", err) } @@ -364,20 +329,24 @@ func (p *Provider) nanoTDFRewrap(body *RequestBody) (*kaspb.RewrapResponse, erro pubKeyBytes := make([]byte, 1+len(pub.X.Bytes())+len(pub.Y.Bytes())) pubKeyBytes[0] = 0x4 // ID for uncompressed format if copy(pubKeyBytes[1:33], pub.X.Bytes()) != 32 || copy(pubKeyBytes[33:], pub.Y.Bytes()) != 32 { + slog.Error("GenerateEphemeralKasKeys", "err", fmt.Errorf("failed to serialize keypair: %v", pub)) return nil, fmt.Errorf("failed to serialize keypair: %v", pub) } privateKeyHandle, publicKeyHandle, err := p.CryptoProvider.GenerateEphemeralKasKeys() if err != nil { + slog.Error("GenerateEphemeralKasKeys", "err", err) return nil, fmt.Errorf("failed to generate keypair: %w", err) } sessionKey, err := p.CryptoProvider.GenerateNanoTDFSessionKey(privateKeyHandle, pubKeyBytes) if err != nil { + slog.Error("GenerateNanoTDFSessionKey", "err", err) return nil, fmt.Errorf("failed to generate session key: %w", err) } cipherText, err := wrapKeyAES(sessionKey, symmetricKey) if err != nil { + slog.Error("wrapKeyAES", "err", err) return nil, fmt.Errorf("failed to encrypt key: %w", err) } @@ -385,11 +354,13 @@ func (p *Provider) nanoTDFRewrap(body *RequestBody) (*kaspb.RewrapResponse, erro //https://github.com/wqx0532/hyperledger-fabric-gm-1/blob/master/bccsp/pkcs11/pkcs11.go#L480 pubGoKey, err := ecdh.P256().NewPublicKey(publicKeyHandle[2:]) if err != nil { + slog.Error("NewPublicKey", "err", err) return nil, fmt.Errorf("failed to make public key") // Handle error, e.g., invalid public key format } pbk, err := x509.MarshalPKIXPublicKey(pubGoKey) if err != nil { + slog.Error("MarshalPKIXPublicKey", "err", err) return nil, fmt.Errorf("failed to convert public Key to PKIX") } diff --git a/service/kas/kas.go b/service/kas/kas.go index e45bcc971..8aeb826c8 100644 --- a/service/kas/kas.go +++ b/service/kas/kas.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/url" - "strings" kaspb "github.com/arkavo-org/opentdf-platform/protocol/go/kas" "github.com/arkavo-org/opentdf-platform/service/kas/access" @@ -17,12 +16,8 @@ func NewRegistration() serviceregistry.Registration { Namespace: "kas", ServiceDesc: &kaspb.AccessService_ServiceDesc, RegisterFunc: func(srp serviceregistry.RegistrationParams) (any, serviceregistry.HandlerServer) { - // FIXME msg="mismatched key access url" keyAccessURL=http://localhost:9000 kasURL=https://:9000 hostWithPort := srp.OTDF.HTTPServer.Addr - if strings.HasPrefix(hostWithPort, ":") { - hostWithPort = "localhost" + hostWithPort - } - kasURLString := "http://" + hostWithPort + kasURLString := "https://" + hostWithPort kasURI, err := url.Parse(kasURLString) if err != nil { panic(fmt.Errorf("invalid kas address [%s] %w", kasURLString, err)) @@ -33,6 +28,7 @@ func NewRegistration() serviceregistry.Registration { AttributeSvc: nil, CryptoProvider: srp.OTDF.CryptoProvider, SDK: srp.SDK, + Config: &srp.Config, } return &p, func(ctx context.Context, mux *runtime.ServeMux, server any) error { kas, ok := server.(*access.Provider)