Skip to content

Commit

Permalink
seeded private-key
Browse files Browse the repository at this point in the history
  • Loading branch information
led0nk committed Feb 3, 2025
1 parent 15ce052 commit 8874875
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 37 deletions.
46 changes: 24 additions & 22 deletions opcua_plugin/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ func (g *OPCUAInput) orderEndpoints(
for _, endpoint := range endpoints {
if isUserTokenSupported(endpoint, selectedAuthentication) {
switch {
case isSignAndEncryptbasic256Sha256Endpoint(endpoint):
case isSignAndEncryptBasic256Sha256Endpoint(endpoint):
signAndEncryptBasic256Sha256Endpoints = append(signAndEncryptBasic256Sha256Endpoints, endpoint)
case isSignBasic256Sha256Endpoint(endpoint):
signBasic256Sha256Endpoints = append(signBasic256Sha256Endpoints, endpoint)
case isSignAndEncryptbasic256Endpoint(endpoint):
case isSignAndEncryptBasic256Endpoint(endpoint):
signAndEncryptBasic256Endpoints = append(signAndEncryptBasic256Endpoints, endpoint)
case isSignBasic256Endpoint(endpoint):
signBasic256Endpoints = append(signBasic256Endpoints, endpoint)
case isSignAndEncryptbasic128Rsa15Endpoint(endpoint):
case isSignAndEncryptBasic128Rsa15Endpoint(endpoint):
signAndEncryptBasic128Rsa15Endpoints = append(signAndEncryptBasic128Rsa15Endpoints, endpoint)
case isSignBasic128Rsa15Endpoint(endpoint):
signBasic128Rsa15Endpoints = append(signBasic128Rsa15Endpoints, endpoint)
Expand Down Expand Up @@ -68,41 +68,41 @@ func isUserTokenSupported(endpoint *ua.EndpointDescription, selectedAuth ua.User
return false
}

// isSignAndEncryptbasic256Sha256Endpoint checks if the endpoint is configured with SignAndEncrypt and Basic256Sha256 security.
func isSignAndEncryptbasic256Sha256Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeFromString("SignAndEncrypt") &&
endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"
// isSignAndEncryptBasic256Sha256Endpoint checks if the endpoint is configured with SignAndEncrypt and Basic256Sha256 security.
func isSignAndEncryptBasic256Sha256Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeSignAndEncrypt &&
endpoint.SecurityPolicyURI == ua.SecurityPolicyURIBasic256Sha256
}

func isSignBasic256Sha256Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeFromString("Sign") &&
endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"
return endpoint.SecurityMode == ua.MessageSecurityModeSign &&
endpoint.SecurityPolicyURI == ua.SecurityPolicyURIBasic256Sha256
}

func isSignAndEncryptbasic256Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeFromString("SignAndEncrypt") &&
endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#Basic256"
func isSignAndEncryptBasic256Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeSignAndEncrypt &&
endpoint.SecurityPolicyURI == ua.SecurityPolicyURIBasic256
}

func isSignBasic256Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeFromString("Sign") &&
endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#Basic256"
return endpoint.SecurityMode == ua.MessageSecurityModeSign &&
endpoint.SecurityPolicyURI == ua.SecurityPolicyURIBasic256
}

func isSignAndEncryptbasic128Rsa15Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeFromString("SignAndEncrypt") &&
endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"
func isSignAndEncryptBasic128Rsa15Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeSignAndEncrypt &&
endpoint.SecurityPolicyURI == ua.SecurityPolicyURIBasic128Rsa15
}

func isSignBasic128Rsa15Endpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeFromString("Sign") &&
endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"
return endpoint.SecurityMode == ua.MessageSecurityModeSign &&
endpoint.SecurityPolicyURI == ua.SecurityPolicyURIBasic128Rsa15
}

// isNoSecurityEndpoint checks if the endpoint has no security configured.
func isNoSecurityEndpoint(endpoint *ua.EndpointDescription) bool {
return endpoint.SecurityMode == ua.MessageSecurityModeFromString("None") &&
endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#None"
return endpoint.SecurityMode == ua.MessageSecurityModeNone &&
endpoint.SecurityPolicyURI == ua.SecurityPolicyURINone
}

// getEndpointIfExists searches within the provided endpoints for a suitable OPC UA endpoint.
Expand All @@ -126,7 +126,9 @@ func (g *OPCUAInput) getEndpointIfExists(
for _, userIdentity := range endpoint.UserIdentityTokens {

// Match the endpoint with the selected authentication type.
if selectedAuthentication == userIdentity.TokenType && endpoint.SecurityPolicyURI == "http://opcfoundation.org/UA/SecurityPolicy#"+securityPolicy && endpoint.SecurityMode == ua.MessageSecurityModeFromString(securityMode) {
if selectedAuthentication == userIdentity.TokenType &&
endpoint.SecurityPolicyURI == ua.FormatSecurityPolicyURI(securityPolicy) &&
endpoint.SecurityMode == ua.MessageSecurityModeFromString(securityMode) {

return endpoint, nil
}
Expand Down
9 changes: 2 additions & 7 deletions opcua_plugin/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
Expand All @@ -14,7 +13,6 @@ import (

"github.com/gopcua/opcua"
"github.com/gopcua/opcua/ua"
"golang.org/x/crypto/sha3"
)

// GetOPCUAClientOptions constructs the OPC UA client options based on the selected endpoint and authentication method.
Expand Down Expand Up @@ -48,11 +46,8 @@ func (g *OPCUAInput) GetOPCUAClientOptions(selectedEndpoint *ua.EndpointDescript
g.CertificateSeed = randomString(8)
}

hashedSeed := sha3.Sum512([]byte(g.CertificateSeed))
hashedSeedString := hex.EncodeToString(hashedSeed[:])

clientName := "urn:benthos-umh-test:client-predefined-" + hashedSeedString[:8]
certPEM, keyPEM, err := GenerateCertWithMode(clientName, 24*time.Hour*365*10, g.SecurityMode, g.SecurityPolicy, hashedSeed)
clientName := "urn:benthos-umh:client-predefined-" + randomString(8)
certPEM, keyPEM, err := GenerateCertWithMode(clientName, 24*time.Hour*365*10, g.SecurityMode, g.SecurityPolicy, g.CertificateSeed)
if err != nil {
g.Log.Errorf("Failed to generate certificate: %v", err)
return nil, err
Expand Down
17 changes: 9 additions & 8 deletions opcua_plugin/generate_cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"hash/fnv"
"io"
"math/big"
mrand "math/rand"
Expand All @@ -26,16 +27,13 @@ import (
"os"
"strings"
"time"

"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/sha3"
)

type seededReader struct {
src *mrand.Rand
}

func NewSeededReader(seed int64) io.Reader {
func newSeededReader(seed int64) io.Reader {
return &seededReader{src: mrand.New(mrand.NewSource(seed))}
}

Expand All @@ -59,7 +57,7 @@ func GenerateCertWithMode(
validFor time.Duration,
securityMode string,
securityPolicy string,
hashedSeed [64]byte,
seedString string,
) (certPEM, keyPEM []byte, err error) {
var rsaBits int

Expand All @@ -83,16 +81,18 @@ func GenerateCertWithMode(
rsaBits = 2048
}

hashhash := sha3.Sum256([]byte("test"))
h := fnv.New64a()
h.Write([]byte(seedString))
seed := int64(h.Sum64())

reader := hkdf.New(sha3.New256, hashhash[:], nil, nil)
seededReader := newSeededReader(seed)

// Create a custom io.Reader to ensure we don't use random Numbers to create
// the private key, but instead use the 'certificateSeed'.
//determReader := newDeterministicReader(hashedSeed)

// Generate RSA private key
priv, err := rsa.GenerateKey(reader, rsaBits)
priv, err := rsa.GenerateKey(seededReader, rsaBits)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate private key: %w", err)
}
Expand Down Expand Up @@ -154,6 +154,7 @@ func GenerateCertWithMode(

// Actually create the certificate
derBytes, err := x509.CreateCertificate(
//NOTE: do we also want to seed the certificate?
rand.Reader,
&template,
&template, // self-signed
Expand Down

0 comments on commit 8874875

Please sign in to comment.