package libebics import ( "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "os" "time" ) type EbicsCertificateType int const ( A005 EbicsCertificateType = iota A006 X002 E002 ) func (t EbicsCertificateType) String() string { switch t { case A005: return "A005" case A006: return "A006" case X002: return "X002" case E002: return "E002" default: panic("invalid EbicsCertificateType") } } 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", sha256.Sum256(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") } }