summaryrefslogtreecommitdiff
path: root/certificate.go
diff options
context:
space:
mode:
Diffstat (limited to 'certificate.go')
-rw-r--r--certificate.go155
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")
+ }
+}