Skip to content

Commit

Permalink
Merge pull request #681 from jackchenjc/issue-671
Browse files Browse the repository at this point in the history
feat: add support for AuthPrivateKey
  • Loading branch information
kung-foo committed Sep 5, 2023
2 parents 10b83a7 + 27c7e61 commit fd06ca1
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 11 deletions.
10 changes: 10 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,16 @@ func AuthCertificate(cert []byte) Option {
}
}

// AuthPrivateKey sets the client's authentication RSA private key
// Note: PolicyID still needs to be set outside of this method, typically through
// the SecurityFromEndpoint() Option
func AuthPrivateKey(key *rsa.PrivateKey) Option {
return func(cfg *Config) error {
cfg.sechan.UserKey = key
return nil
}
}

// AuthIssuedToken sets the client's authentication data based on an externally-issued token
// Note: PolicyID still needs to be set outside of this method, typically through
// the SecurityFromEndpoint() Option
Expand Down
11 changes: 11 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,17 @@ func TestOptions(t *testing.T) {
}(),
},
},
{
name: `AuthPrivateKey()`,
opt: AuthPrivateKey(cert.PrivateKey.(*rsa.PrivateKey)),
cfg: &Config{
sechan: func() *uasc.Config {
c := DefaultClientConfig()
c.UserKey = cert.PrivateKey.(*rsa.PrivateKey)
return c
}(),
},
},
{
name: `AuthIssuedToken()`,
opt: AuthIssuedToken([]byte("a")),
Expand Down
25 changes: 15 additions & 10 deletions examples/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ func clientOptsFromFlags(endpoints []*ua.EndpointDescription) []opcua.Option {
}

var cert []byte
var privateKey *rsa.PrivateKey
if *gencert || (*certfile != "" && *keyfile != "") {
if *gencert {
certPEM, keyPEM, err := uatest.GenerateCert(*appuri, 2048, 24*time.Hour)
Expand All @@ -148,6 +149,7 @@ func clientOptsFromFlags(endpoints []*ua.EndpointDescription) []opcua.Option {
log.Fatalf("Invalid private key")
}
cert = c.Certificate[0]
privateKey = pk
opts = append(opts, opcua.PrivateKey(pk), opcua.Certificate(cert))
}
}
Expand All @@ -167,8 +169,8 @@ func clientOptsFromFlags(endpoints []*ua.EndpointDescription) []opcua.Option {
}

// Select the most appropriate authentication mode from server capabilities and user input
authMode, authOption := authFromFlags(cert)
opts = append(opts, authOption)
authMode, authOptions := authFromFlags(cert, privateKey)
opts = append(opts, authOptions...)

var secMode ua.MessageSecurityMode
switch strings.ToLower(*mode) {
Expand Down Expand Up @@ -246,15 +248,15 @@ func clientOptsFromFlags(endpoints []*ua.EndpointDescription) []opcua.Option {
return opts
}

func authFromFlags(cert []byte) (ua.UserTokenType, opcua.Option) {
func authFromFlags(cert []byte, pk *rsa.PrivateKey) (ua.UserTokenType, []opcua.Option) {
var err error

var authMode ua.UserTokenType
var authOption opcua.Option
var authOptions []opcua.Option
switch strings.ToLower(*auth) {
case "anonymous":
authMode = ua.UserTokenTypeAnonymous
authOption = opcua.AuthAnonymous()
authOptions = append(authOptions, opcua.AuthAnonymous())

case "username":
authMode = ua.UserTokenTypeUserName
Expand Down Expand Up @@ -284,25 +286,28 @@ func authFromFlags(cert []byte) (ua.UserTokenType, opcua.Option) {
*password = string(passInput)
fmt.Print("\n")
}
authOption = opcua.AuthUsername(*username, *password)
authOptions = append(authOptions, opcua.AuthUsername(*username, *password))

case "certificate":
authMode = ua.UserTokenTypeCertificate
authOption = opcua.AuthCertificate(cert)
// Note: You should still use these two Config options to load the auth certificate and private key
// separately from the secure channel configuration even if the same certificate is used for both purposes
authOptions = append(authOptions, opcua.AuthCertificate(cert))
authOptions = append(authOptions, opcua.AuthPrivateKey(pk))

case "issuedtoken":
// todo: this is unsupported, fail here or fail in the opcua package?
authMode = ua.UserTokenTypeIssuedToken
authOption = opcua.AuthIssuedToken([]byte(nil))
authOptions = append(authOptions, opcua.AuthIssuedToken([]byte(nil)))

default:
log.Printf("unknown auth-mode, defaulting to Anonymous")
authMode = ua.UserTokenTypeAnonymous
authOption = opcua.AuthAnonymous()
authOptions = append(authOptions, opcua.AuthAnonymous())

}

return authMode, authOption
return authMode, authOptions
}

func validateEndpointConfig(endpoints []*ua.EndpointDescription, secPolicy string, secMode ua.MessageSecurityMode, authMode ua.UserTokenType) error {
Expand Down
4 changes: 4 additions & 0 deletions uasc/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ type Config struct {
// messages. It is the key associated with Certificate
LocalKey *rsa.PrivateKey

// UserKey is a RSA Private Key which will be used to sign the UserTokenSignature.
// It is the key associated with AuthCertificate
UserKey *rsa.PrivateKey

// Thumbprint is the thumbprint of the X.509 v3 Certificate assigned to the receiving
// application Instance.
// The thumbprint is the CertificateDigest of the DER encoded form of the
Expand Down
2 changes: 1 addition & 1 deletion uasc/secure_channel_crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (s *SecureChannel) NewUserTokenSignature(policyURI string, cert, nonce []by
}
remoteKey := remoteX509Cert.PublicKey.(*rsa.PublicKey)

enc, err := uapolicy.Asymmetric(policyURI, s.cfg.LocalKey, remoteKey)
enc, err := uapolicy.Asymmetric(policyURI, s.cfg.UserKey, remoteKey)
if err != nil {
return nil, "", err
}
Expand Down

0 comments on commit fd06ca1

Please sign in to comment.