add openpgp keyring config
This commit is contained in:
parent
d305305fab
commit
8e85305595
@ -1,90 +0,0 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"crypto/rsa"
|
||||
"crypto/rand"
|
||||
"encoding/pem"
|
||||
"encoding/json"
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
type OpenPGP struct {
|
||||
Armored string
|
||||
entities openpgp.EntityList
|
||||
}
|
||||
|
||||
func (o *OpenPGP) Read() (yamlData []byte, err error) {
|
||||
pemReader := io.NopCloser(strings.NewReader(o.Armored))
|
||||
o.entities, err = openpgp.ReadArmoredKeyRing(pemReader)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func (o *OpenPGP) UnmarshalJSON(data []byte) error {
|
||||
if unmarshalErr := json.Unmarshal(data, o); unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGP) UnmarshalYAML(value *yaml.Node) error {
|
||||
type decodeOpenPGP OpenPGP
|
||||
if unmarshalErr := value.Decode((*decodeOpenPGP)(o)); unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGP) Clone() data.Configuration {
|
||||
jsonGeneric, _ := json.Marshal(c)
|
||||
clone := NewOpenPGP()
|
||||
if unmarshalErr := json.Unmarshal(jsonGeneric, &clone); unmarshalErr != nil {
|
||||
panic(unmarshalErr)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func (o *OpenPGP) Type() string {
|
||||
return "openpgp"
|
||||
}
|
||||
|
||||
func (o *OpenPGP) GetEntityIndex(key string) (index int, field string, err error) {
|
||||
values := strings.SplitN(key, ".", 2)
|
||||
if len(values) == 2 {
|
||||
if index, err = strconv.Atoi(values[0]); err == nil {
|
||||
field = values[1]
|
||||
}
|
||||
} else {
|
||||
err = data.ErrUnknownConfigurationKey
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OpenPGP) GetValue(name string) (result any, err error) {
|
||||
var ok bool
|
||||
if result, ok = (*c)[name]; !ok {
|
||||
err = data.ErrUnknownConfigurationKey
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Expected key: 0.PrivateKey
|
||||
func (o *OpenPGP) Has(key string) (ok bool) {
|
||||
index, field, err := o.GetEntityIndex(key)
|
||||
if len(o.entities) > index && err == nil {
|
||||
switch key {
|
||||
case PublicKey:
|
||||
ok = o.entities[index].PrimaryKey != nil
|
||||
case PrivateKey:
|
||||
ok = o.entities[index].PrimaryKey != nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"crypto/x509"
|
||||
)
|
||||
|
||||
func TestNewOpenPGPConfig(t *testing.T) {
|
||||
p := NewOpenPGP()
|
||||
assert.NotNil(t, p)
|
||||
}
|
||||
|
||||
func TestNewOpenPGPConfigYAML(t *testing.T) {
|
||||
p := NewOpenPGP()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
config := `
|
||||
openpgp:
|
||||
publickey:
|
||||
|
||||
`
|
||||
|
||||
yamlErr := c.LoadYAML(config)
|
||||
assert.Nil(t, yamlErr)
|
||||
crt, err := c.GetValue("catemplate")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []string{"RKH"}, crt.(*x509.Certificate).Subject.Organization)
|
||||
}
|
134
internal/config/openpgpkeyring.go
Normal file
134
internal/config/openpgpkeyring.go
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
|
||||
"io"
|
||||
"strings"
|
||||
"strconv"
|
||||
"gopkg.in/yaml.v3"
|
||||
"decl/internal/data"
|
||||
"decl/internal/codec"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
type OpenPGPKeyRing struct {
|
||||
Keyring string `json:"keyring,omitempty" yaml:"keyring,omitempty"`
|
||||
entities openpgp.EntityList
|
||||
}
|
||||
|
||||
func NewOpenPGPKeyRing() *OpenPGPKeyRing {
|
||||
o := &OpenPGPKeyRing{}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) URI() string {
|
||||
return fmt.Sprintf("%s://%s", o.Type(), "")
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) SetURI(uri string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) SetParsedURI(uri data.URIParser) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) Read(ctx context.Context) (yamlData []byte, err error) {
|
||||
pemReader := io.NopCloser(strings.NewReader(o.Keyring))
|
||||
o.entities, err = openpgp.ReadArmoredKeyRing(pemReader)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) Load(r io.Reader) (err error) {
|
||||
err = codec.NewYAMLDecoder(r).Decode(o)
|
||||
if err == nil {
|
||||
_, err = o.Read(context.Background())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) LoadYAML(yamlData string) (err error) {
|
||||
err = codec.NewYAMLStringDecoder(yamlData).Decode(o)
|
||||
slog.Info("OpenPGP.LoadYAML()", "keyring", len(o.Keyring), "err", err)
|
||||
if err == nil {
|
||||
_, err = o.Read(context.Background())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) UnmarshalJSON(data []byte) error {
|
||||
if unmarshalErr := json.Unmarshal(data, o); unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
//o.NewReadConfigCommand()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) UnmarshalYAML(value *yaml.Node) error {
|
||||
type decodeOpenPGP OpenPGPKeyRing
|
||||
if unmarshalErr := value.Decode((*decodeOpenPGP)(o)); unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) Clone() data.Configuration {
|
||||
jsonGeneric, _ := json.Marshal(o)
|
||||
clone := NewOpenPGPKeyRing()
|
||||
if unmarshalErr := json.Unmarshal(jsonGeneric, &clone); unmarshalErr != nil {
|
||||
panic(unmarshalErr)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) Type() string {
|
||||
return "openpgp"
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) GetEntityIndex(key string) (index int, field string, err error) {
|
||||
values := strings.SplitN(key, ".", 2)
|
||||
if len(values) == 2 {
|
||||
if index, err = strconv.Atoi(values[0]); err == nil {
|
||||
field = values[1]
|
||||
}
|
||||
} else {
|
||||
err = data.ErrUnknownConfigurationKey
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OpenPGPKeyRing) GetValue(name string) (result any, err error) {
|
||||
index, field, err := o.GetEntityIndex(name)
|
||||
if len(o.entities) > index && err == nil {
|
||||
switch field {
|
||||
case "PublicKey":
|
||||
return o.entities[index].PrimaryKey, err
|
||||
case "PrivateKey":
|
||||
return o.entities[index].PrimaryKey, err
|
||||
}
|
||||
}
|
||||
err = data.ErrUnknownConfigurationKey
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Expected key: 0.PrivateKey
|
||||
func (o *OpenPGPKeyRing) Has(key string) (ok bool) {
|
||||
index, field, err := o.GetEntityIndex(key)
|
||||
if len(o.entities) > index && err == nil {
|
||||
switch field {
|
||||
case "PublicKey":
|
||||
ok = o.entities[index].PrimaryKey != nil
|
||||
case "PrivateKey":
|
||||
ok = o.entities[index].PrimaryKey != nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
131
internal/config/openpgpkeyring_test.go
Normal file
131
internal/config/openpgpkeyring_test.go
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
privateKey = `
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
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
|
||||
=BAfD
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
`
|
||||
publicKey = `
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
xsBNBGhI/VUBCADDVSm3mKY5JsncMMJFV0zELMrmip7dkK3vvMvVWVmMHiC4akDH
|
||||
WPxUdWNQPjE2e5HGF9Ebg0c7gu634VG470MnTzFdPV6f5zA+yJfdKrLq7gpl9QGW
|
||||
jFLIeK/l4xc+MIpOE1rD9WqYUUw2IYY8YANYq4yB36rq41VuZps/adI9Go5IhfcU
|
||||
3SVb7o7pa/gWE0FVu9ze31j2agC8FIKHgB++7bmYgbAQz5Qi1qgtG0Kn25QUacJ6
|
||||
Akm2+h4w3SQCR6HLRV2BO29x9mFBszf2KQ7DW2VNiGyUuQQ3m8v2ZidG/11ff6U6
|
||||
ad5tvr/8sYr5jOnKEJyDP9v9yQ04cU94GmsPABEBAAHNL1Rlc3RVc2VyMSAoVGVz
|
||||
dFVzZXIxKSA8dGVzdHVzZXJAcm9zc2tlZW4uaG91c2U+wsCKBBMBCAA+BQJoSP1V
|
||||
CRDfB5I2FtNl1xYhBADOnA8Aah3FXyl/m98HkjYW02XXAhsDAh4BAhkBAgsHAhUI
|
||||
AxYAAgMnBwIAAGKLB/9whwgfLkoTYI+Q0Te2uZXl7FPyW0t4tbUSoI1aiVw+ymND
|
||||
V+wuqYsjYDob2MyK/TAFkSCqZhBIRbGLRJtwzQwkF/amGuelHSSBX3LdxK/sp2UU
|
||||
+zv/NBEP1LlUNKchuxpdBPYjKHdbOLPoKqFfdCujSxpWTIeKCwvnDtuP+PlsjUgc
|
||||
afxMx+cVwe77AZ1Fi5CBD9Dr7nNsLovywrSiszyVh5eT0pbcu8Elf5oYQNT1q3ms
|
||||
aqrw95shlGQiwVgrfTvRCDeZnKafHwMUoh48otsNI9aS0HpChi+JNd+PLe/Wlsj5
|
||||
x+q0sHc+5/24zQvN0Wx9fPE4/7z8Pr+CUhAxjI7hzsBNBGhI/VUBCACfahoi2GRx
|
||||
OfOqJ4ZN8Te+4bJeOQdzTofAisfCU736q+MvEKtAuY72vzWdERWpn7XABmtkfII8
|
||||
Xyya8iHKuEGCETy0YoZ15GLBgSHhLnlN2U/4BkrUjGvUjZWquW22gfFB1q8ZdSGw
|
||||
pg8hrspY/b+nnAGdawq+hfE6YRQTmG5tkBrctxfxglBnKzezmL1a3arTHWf2SRlL
|
||||
eAWNI4sACryP/5plD6+9Z9YXTKeDlXnga6BzB80y7F2g0cPdtX20dWAGx4irq2I2
|
||||
SxlABvWMZrdm2Upr6yLHD2zTpbf1FkKFUw9j0lrL1fMq0/j9zbKJsTh6CtOlF04s
|
||||
AeoEV9SZ36GvABEBAAHCwHYEGAEIACoFAmhI/VUJEN8HkjYW02XXFiEEAM6cDwBq
|
||||
HcVfKX+b3weSNhbTZdcCGwwAAFxWB/9Af7qpYKldDz5iNYQluFoPfyHAVlOpiakf
|
||||
hvnu7hijTEgB1frByKu2m+k4m7gANBgfWldsYi1feWBVn6fspXuCc0k7opmQgol7
|
||||
ueTrsGnNB7U0l14HcKSTLZ2c/Jt7ZS6aXXjxpYPq0/5lt8+5sRkXxHI9HhAx6gK/
|
||||
RJCNITRt/V/gT4YWWbz8VHgkPIfHFsjr8brVhm4V/+JKZAG4eSNQp4QrTpdIjdfa
|
||||
1rd91qffyrWhPNTQErE2jFOXSU/OojdDjGJ7pwr0qj4FHACVL3/oqYog2NrUWf92
|
||||
QcwwWrEZNZUpJEMUB5q+tOoZ40ll0A8lsvABULZDqWveYpRQF+rQ
|
||||
=jBvZ
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
`
|
||||
)
|
||||
|
||||
func TestNewOpenPGPKeyRingConfig(t *testing.T) {
|
||||
p := NewOpenPGPKeyRing()
|
||||
assert.NotNil(t, p)
|
||||
}
|
||||
|
||||
func TestNewOpenPGPKeyRingConfigYAML(t *testing.T) {
|
||||
p := NewOpenPGPKeyRing()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
config := fmt.Sprintf(`
|
||||
keyring: |-
|
||||
%s
|
||||
%s
|
||||
`, publicKey, privateKey)
|
||||
|
||||
yamlErr := p.LoadYAML(config)
|
||||
assert.Nil(t, yamlErr)
|
||||
|
||||
/*
|
||||
crt, err := p.GetValue("catemplate")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []string{"RKH"}, crt.(*x509.Certificate).Subject.Organization)
|
||||
*/
|
||||
|
||||
}
|
135
internal/config/openpgpsignature.go
Normal file
135
internal/config/openpgpsignature.go
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/ProtonMail/go-crypto/openpgp"
|
||||
|
||||
"io"
|
||||
"strings"
|
||||
"strconv"
|
||||
"gopkg.in/yaml.v3"
|
||||
"decl/internal/data"
|
||||
"decl/internal/codec"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
type OpenPGPSignature struct {
|
||||
KeyRing string `json:"keyring,omitempty" yaml:"keyring,omitempty"`
|
||||
Signature string `json:"signature,omitempty" yaml:"signature,omitempty"`
|
||||
entities openpgp.EntityList
|
||||
}
|
||||
|
||||
func NewOpenPGPSignature() *OpenPGPSignature {
|
||||
o := &OpenPGPSignature{}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) URI() string {
|
||||
return fmt.Sprintf("%s://%s", o.Type(), "")
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) SetURI(uri string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) SetParsedURI(uri data.URIParser) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) Read(ctx context.Context) (yamlData []byte, err error) {
|
||||
pemReader := io.NopCloser(strings.NewReader(o.KeyRing))
|
||||
o.entities, err = openpgp.ReadArmoredKeyRing(pemReader)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) Load(r io.Reader) (err error) {
|
||||
err = codec.NewYAMLDecoder(r).Decode(o)
|
||||
if err == nil {
|
||||
_, err = o.Read(context.Background())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) LoadYAML(yamlData string) (err error) {
|
||||
err = codec.NewYAMLStringDecoder(yamlData).Decode(o)
|
||||
slog.Info("OpenPGP.LoadYAML()", "keyring", len(o.KeyRing), "err", err)
|
||||
if err == nil {
|
||||
_, err = o.Read(context.Background())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) UnmarshalJSON(data []byte) error {
|
||||
if unmarshalErr := json.Unmarshal(data, o); unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
//o.NewReadConfigCommand()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) UnmarshalYAML(value *yaml.Node) error {
|
||||
type decodeOpenPGP OpenPGPSignature
|
||||
if unmarshalErr := value.Decode((*decodeOpenPGP)(o)); unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) Clone() data.Configuration {
|
||||
jsonGeneric, _ := json.Marshal(o)
|
||||
clone := NewOpenPGPSignature()
|
||||
if unmarshalErr := json.Unmarshal(jsonGeneric, &clone); unmarshalErr != nil {
|
||||
panic(unmarshalErr)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) Type() string {
|
||||
return "openpgp"
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) GetEntityIndex(key string) (index int, field string, err error) {
|
||||
values := strings.SplitN(key, ".", 2)
|
||||
if len(values) == 2 {
|
||||
if index, err = strconv.Atoi(values[0]); err == nil {
|
||||
field = values[1]
|
||||
}
|
||||
} else {
|
||||
err = data.ErrUnknownConfigurationKey
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *OpenPGPSignature) GetValue(name string) (result any, err error) {
|
||||
index, field, err := o.GetEntityIndex(name)
|
||||
if len(o.entities) > index && err == nil {
|
||||
switch field {
|
||||
case "PublicKey":
|
||||
return o.entities[index].PrimaryKey, err
|
||||
case "PrivateKey":
|
||||
return o.entities[index].PrimaryKey, err
|
||||
}
|
||||
}
|
||||
err = data.ErrUnknownConfigurationKey
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Expected key: 0.PrivateKey
|
||||
func (o *OpenPGPSignature) Has(key string) (ok bool) {
|
||||
index, field, err := o.GetEntityIndex(key)
|
||||
if len(o.entities) > index && err == nil {
|
||||
switch field {
|
||||
case "PublicKey":
|
||||
ok = o.entities[index].PrimaryKey != nil
|
||||
case "PrivateKey":
|
||||
ok = o.entities[index].PrimaryKey != nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
33
internal/config/openpgpsignature_test.go
Normal file
33
internal/config/openpgpsignature_test.go
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func TestNewOpenPGPSignatureConfig(t *testing.T) {
|
||||
p := NewOpenPGPSignature()
|
||||
assert.NotNil(t, p)
|
||||
}
|
||||
|
||||
func TestNewOpenPGPSignatureConfigYAML(t *testing.T) {
|
||||
p := NewOpenPGPSignature()
|
||||
assert.NotNil(t, p)
|
||||
|
||||
|
||||
|
||||
config := fmt.Sprintf(`
|
||||
keyring: |-
|
||||
%s
|
||||
%s
|
||||
`, publicKey, privateKey)
|
||||
|
||||
yamlErr := p.LoadYAML(config)
|
||||
assert.Nil(t, yamlErr)
|
||||
|
||||
p.Read(context.Background())
|
||||
}
|
9
internal/config/schemas/openpgp.schema.json
Normal file
9
internal/config/schemas/openpgp.schema.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"$id": "openpgp.schema.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "openpgp",
|
||||
"type": "object",
|
||||
"required": [ "path", "filetype" ],
|
||||
"properties": {
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ func NewSystem() *System {
|
||||
s["importpath"] = []string {
|
||||
"/etc/jx/lib",
|
||||
}
|
||||
s["keyringpath"] = "/etc/jx/pgp/keyring.asc"
|
||||
return &s
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user