diff options
Diffstat (limited to 'certificate.go')
| -rw-r--r-- | certificate.go | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/certificate.go b/certificate.go new file mode 100644 index 0000000..72a823a --- /dev/null +++ b/certificate.go @@ -0,0 +1,155 @@ +package main + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "os" + "time" +) + +type EbicsCertificateType int + +const ( + A005 EbicsCertificateType = iota + A006 + X002 + E002 +) + +type EbicsCertificate struct { + x509Certificate []byte + ebicsCertificateType EbicsCertificateType +} + +func GenerateSelfSignedCertificate(ebicsCertificateType EbicsCertificateType, privateKey rsa.PrivateKey) (*EbicsCertificate, error) { + var keyUsage x509.KeyUsage + + switch ebicsCertificateType { + case X002: + keyUsage = x509.KeyUsageDigitalSignature + case E002: + keyUsage = x509.KeyUsageKeyEncipherment + case A005, A006: + keyUsage = x509.KeyUsageContentCommitment + default: + return nil, fmt.Errorf("certificate type not implemented") + } + + template := x509.Certificate{ + Subject: pkix.Name{ + CommonName: "SCHOLZ01", + }, + NotBefore: time.Now(), + NotAfter: time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC), + KeyUsage: keyUsage, + } + + x509Certificate, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, &privateKey) + if err != nil { + return nil, err + } + + return &EbicsCertificate{ + x509Certificate: x509Certificate, + ebicsCertificateType: ebicsCertificateType, + }, nil +} + +func GetCertificateFingerprintAsString(ebicsCertificate *EbicsCertificate) string { + return fmt.Sprintf("% x", sha1.Sum(ebicsCertificate.x509Certificate)) +} + +func WriteCertificateToFile(ebicsCertificate *EbicsCertificate, path string) error { + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + + return pem.Encode(f, &pem.Block{ + Type: "CERTIFICATE", + Bytes: ebicsCertificate.x509Certificate, + }) +} + +func ReadCertificateFromFile(path string, ebicsCertificateType EbicsCertificateType) (*EbicsCertificate, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + block, _ := pem.Decode(data) + if block == nil { + return nil, fmt.Errorf("no PEM data found") + } + if block.Type != "CERTIFICATE" { + return nil, fmt.Errorf("unexpected PEM type: %s", block.Type) + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + + var keyUsage x509.KeyUsage + switch ebicsCertificateType { + case X002: + keyUsage = x509.KeyUsageDigitalSignature + case E002: + keyUsage = x509.KeyUsageKeyEncipherment + case A005, A006: + keyUsage = x509.KeyUsageContentCommitment + } + + if cert.KeyUsage != keyUsage { + return nil, fmt.Errorf("expected KeyUsage %s does not match KeyUsage in loaded Certificate (%s)", keyUsage, cert.KeyUsage) + } + + return &EbicsCertificate{ + x509Certificate: cert.Raw, + ebicsCertificateType: ebicsCertificateType, + }, nil +} + +func WriteKeypairToFile(privateKey *rsa.PrivateKey, path string) error { + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + + der, err := x509.MarshalPKCS8PrivateKey(privateKey) + + return pem.Encode(f, &pem.Block{ + Type: "PRIVATE KEY", + Bytes: der, + }) +} + +func ReadKeypairFromFile(path string) (*rsa.PrivateKey, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + block, _ := pem.Decode(data) + if block == nil { + return nil, fmt.Errorf("no PEM data found") + } + if block.Type != "PRIVATE KEY" { + return nil, fmt.Errorf("unexpected PEM type: %s", block.Type) + } + + privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) + switch privateKey := privateKey.(type) { + case *rsa.PrivateKey: + return privateKey, nil + default: + return nil, fmt.Errorf("private key type not supported") + } +} |
