Skip to content

Commit 677124c

Browse files
authored
change api for work with x509 (#7)
1 parent f5c1fc8 commit 677124c

23 files changed

+1212
-639
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
go.osspkg.com/casecheck v0.3.0
77
go.osspkg.com/errors v0.4.0
88
go.osspkg.com/random v0.5.0
9+
go.osspkg.com/syncing v0.4.3
910
golang.org/x/crypto v0.43.0
1011
)
1112

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ go.osspkg.com/errors v0.4.0 h1:E17+WyUzTXEHCTxGm8lOMPOOojzHG1lsOuQtTVGoATQ=
44
go.osspkg.com/errors v0.4.0/go.mod h1:s75ZovPemYtrCtRPVsbQNq9MgMbmLMK1NEypr+uwjXI=
55
go.osspkg.com/random v0.5.0 h1:6x2CQ5Vb6PVyuGi6Ao3K6Pr2fzVviBPCEEJC5HQNSmg=
66
go.osspkg.com/random v0.5.0/go.mod h1:lsg3FI87PQdjhVWIVo2GXyPBclipljUxjMlWqRl2cck=
7+
go.osspkg.com/syncing v0.4.3 h1:XioXG9zje1LNCsfQhNHkNPCQqPSJZHWTzM8Xig2zvAU=
8+
go.osspkg.com/syncing v0.4.3/go.mod h1:/LBmgCAHFW6nQgVDILpEuo6eRCFK1yyFeNbDs4eVNls=
79
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
810
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
911
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=

pki/alg_ecdsa.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2024-2025 Mikhail Knyazhev <[email protected]>. All rights reserved.
3+
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
4+
*/
5+
6+
package pki
7+
8+
import (
9+
"crypto"
10+
"crypto/ecdsa"
11+
"crypto/elliptic"
12+
"crypto/rand"
13+
"crypto/x509"
14+
"fmt"
15+
"reflect"
16+
)
17+
18+
type _ecdsa struct{}
19+
20+
func (*_ecdsa) Name() x509.PublicKeyAlgorithm {
21+
return x509.ECDSA
22+
}
23+
24+
func (*_ecdsa) IsPrivateKey(key crypto.Signer) bool {
25+
_, ok := key.(*ecdsa.PrivateKey)
26+
return ok
27+
}
28+
29+
func (*_ecdsa) IsCertificate(cert x509.Certificate) bool {
30+
_, ok := cert.PublicKey.(*ecdsa.PublicKey)
31+
return ok
32+
}
33+
34+
func (*_ecdsa) IsRequest(cert x509.CertificateRequest) bool {
35+
_, ok := cert.PublicKey.(*ecdsa.PublicKey)
36+
return ok
37+
}
38+
39+
func (*_ecdsa) IsValidPair(key crypto.Signer, cert x509.Certificate) bool {
40+
raw, ok := key.(*ecdsa.PrivateKey)
41+
if !ok {
42+
return false
43+
}
44+
pk, ok := raw.Public().(*ecdsa.PublicKey)
45+
if !ok {
46+
return false
47+
}
48+
ck, ok := cert.PublicKey.(*ecdsa.PublicKey)
49+
if !ok {
50+
return false
51+
}
52+
53+
return reflect.DeepEqual(pk, ck)
54+
}
55+
56+
func (*_ecdsa) Generate(ct CertType) (crypto.Signer, error) {
57+
var curve elliptic.Curve
58+
switch ct {
59+
case RootCaCert:
60+
curve = elliptic.P256()
61+
case InterCACert:
62+
curve = elliptic.P384()
63+
case ClientCert:
64+
curve = elliptic.P256()
65+
default:
66+
return nil, fmt.Errorf("unknown certificate curve for '%s'", ct)
67+
}
68+
69+
return ecdsa.GenerateKey(curve, rand.Reader)
70+
}

pki/alg_rsa.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) 2024-2025 Mikhail Knyazhev <[email protected]>. All rights reserved.
3+
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
4+
*/
5+
6+
package pki
7+
8+
import (
9+
"crypto"
10+
"crypto/rand"
11+
"crypto/rsa"
12+
"crypto/x509"
13+
"fmt"
14+
"reflect"
15+
)
16+
17+
type _rsa struct{}
18+
19+
func (*_rsa) Name() x509.PublicKeyAlgorithm {
20+
return x509.RSA
21+
}
22+
23+
func (*_rsa) IsPrivateKey(key crypto.Signer) bool {
24+
_, ok := key.(*rsa.PrivateKey)
25+
return ok
26+
}
27+
28+
func (*_rsa) IsCertificate(cert x509.Certificate) bool {
29+
_, ok := cert.PublicKey.(*rsa.PublicKey)
30+
return ok
31+
}
32+
33+
func (*_rsa) IsRequest(cert x509.CertificateRequest) bool {
34+
_, ok := cert.PublicKey.(*rsa.PublicKey)
35+
return ok
36+
}
37+
38+
func (*_rsa) IsValidPair(key crypto.Signer, cert x509.Certificate) bool {
39+
raw, ok := key.(*rsa.PrivateKey)
40+
if !ok {
41+
return false
42+
}
43+
pk, ok := raw.Public().(*rsa.PublicKey)
44+
if !ok {
45+
return false
46+
}
47+
ck, ok := cert.PublicKey.(*rsa.PublicKey)
48+
if !ok {
49+
return false
50+
}
51+
52+
return reflect.DeepEqual(pk, ck)
53+
}
54+
55+
func (*_rsa) Generate(ct CertType) (crypto.Signer, error) {
56+
var bits int
57+
switch ct {
58+
case RootCaCert:
59+
bits = 4096
60+
case InterCACert:
61+
bits = 3072
62+
case ClientCert:
63+
bits = 2048
64+
default:
65+
return nil, fmt.Errorf("unknown certificate bits for '%s'", ct)
66+
}
67+
68+
return rsa.GenerateKey(rand.Reader, bits)
69+
}

pki/alg_type.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) 2024-2025 Mikhail Knyazhev <[email protected]>. All rights reserved.
3+
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
4+
*/
5+
6+
package pki
7+
8+
import (
9+
"crypto"
10+
"crypto/x509"
11+
12+
"go.osspkg.com/syncing"
13+
)
14+
15+
var (
16+
signatures = syncing.NewMap[x509.SignatureAlgorithm, x509.PublicKeyAlgorithm](5)
17+
algorithms = syncing.NewMap[x509.PublicKeyAlgorithm, Algorithm](5)
18+
)
19+
20+
func Register(k x509.SignatureAlgorithm, v Algorithm) {
21+
signatures.Set(k, v.Name())
22+
algorithms.Set(v.Name(), v)
23+
}
24+
25+
func init() {
26+
Register(x509.SHA256WithRSA, &_rsa{})
27+
Register(x509.SHA384WithRSA, &_rsa{})
28+
Register(x509.SHA512WithRSA, &_rsa{})
29+
Register(x509.ECDSAWithSHA256, &_ecdsa{})
30+
Register(x509.ECDSAWithSHA384, &_ecdsa{})
31+
Register(x509.ECDSAWithSHA512, &_ecdsa{})
32+
}
33+
34+
type Algorithm interface {
35+
Name() x509.PublicKeyAlgorithm
36+
IsPrivateKey(key crypto.Signer) bool
37+
IsRequest(cert x509.CertificateRequest) bool
38+
IsCertificate(cert x509.Certificate) bool
39+
IsValidPair(key crypto.Signer, cert x509.Certificate) bool
40+
Generate(ct CertType) (crypto.Signer, error)
41+
}
42+
43+
type CertType string
44+
45+
const (
46+
RootCaCert CertType = "root_ca_cert"
47+
InterCACert CertType = "intermediate_ca_cert"
48+
ClientCert CertType = "client_cert"
49+
)

x509cert/common.go renamed to pki/common.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
44
*/
55

6-
package x509cert
6+
package pki
77

88
import (
99
_ "crypto/md5"

pki/config.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2024-2025 Mikhail Knyazhev <[email protected]>. All rights reserved.
3+
* Use of this source code is governed by a BSD 3-Clause license that can be found in the LICENSE file.
4+
*/
5+
6+
package pki
7+
8+
import (
9+
"crypto/x509"
10+
"crypto/x509/pkix"
11+
"encoding/asn1"
12+
)
13+
14+
type Config struct {
15+
SignatureAlgorithm x509.SignatureAlgorithm `yaml:"signature_algorithm" json:"signature_algorithm"`
16+
17+
Organization string `yaml:"organization,omitempty" json:"organization,omitempty"`
18+
OrganizationalUnit string `yaml:"organizational_unit,omitempty" json:"organizational_unit,omitempty"`
19+
Country string `yaml:"country,omitempty" json:"country,omitempty"`
20+
Province string `yaml:"province,omitempty" json:"province,omitempty"`
21+
Locality string `yaml:"locality,omitempty" json:"locality,omitempty"`
22+
StreetAddress string `yaml:"street_address,omitempty" json:"street_address,omitempty"`
23+
PostalCode string `yaml:"postal_code,omitempty" json:"postal_code,omitempty"`
24+
CommonName string `yaml:"common_name,omitempty" json:"common_name,omitempty"`
25+
26+
EmailAddress []string `yaml:"email_address,omitempty" json:"email_address,omitempty"`
27+
OCSPServerURLs []string `yaml:"ocsp_server_ur_ls,omitempty" json:"ocsp_server_ur_ls,omitempty"`
28+
IssuingCertificateURLs []string `yaml:"issuing_certificate_urls,omitempty" json:"issuing_certificate_urls,omitempty"`
29+
CRLDistributionPointURLs []string `yaml:"crl_distribution_point_ur_ls,omitempty" json:"crl_distribution_point_ur_ls,omitempty"`
30+
CertificatePoliciesURLs []string `yaml:"certificate_policies_urls,omitempty" json:"certificate_policies_urls,omitempty"`
31+
}
32+
33+
func (v Config) Subject() pkix.Name {
34+
result := pkix.Name{}
35+
36+
if len(v.Country) > 0 {
37+
result.Country = []string{v.Country}
38+
}
39+
if len(v.Organization) > 0 {
40+
result.Organization = []string{v.Organization}
41+
}
42+
if len(v.OrganizationalUnit) > 0 {
43+
result.OrganizationalUnit = []string{v.OrganizationalUnit}
44+
}
45+
if len(v.Locality) > 0 {
46+
result.Locality = []string{v.Locality}
47+
}
48+
if len(v.Province) > 0 {
49+
result.Province = []string{v.Province}
50+
}
51+
if len(v.StreetAddress) > 0 {
52+
result.StreetAddress = []string{v.StreetAddress}
53+
}
54+
if len(v.PostalCode) > 0 {
55+
result.PostalCode = []string{v.PostalCode}
56+
}
57+
if len(v.CommonName) > 0 {
58+
result.CommonName = v.CommonName
59+
}
60+
61+
return result
62+
}
63+
64+
func (v Config) ExtraExtensions() []pkix.Extension {
65+
var result []pkix.Extension
66+
67+
if len(v.IssuingCertificateURLs) > 0 {
68+
for _, value := range stringsPrepare(v.CertificatePoliciesURLs) {
69+
result = append(result, pkix.Extension{
70+
Id: asn1.ObjectIdentifier{2, 23, 140, 1, 1},
71+
Critical: true,
72+
Value: []byte(value),
73+
})
74+
}
75+
76+
}
77+
78+
return result
79+
}

0 commit comments

Comments
 (0)