+++ /dev/null
-package main
-
-import (
- "errors"
- "os"
- "time"
-
- "github.com/google/uuid"
- "go.cypherpunks.su/yac/gyac"
-)
-
-type AV struct {
- A string `yac:"a"`
- V []byte `yac:"v"`
-}
-
-type CerTBS struct {
- KU []string `yac:"ku,omitempty"`
- Subj map[string]string `yac:"sub"`
- Exp []time.Time `yac:"exp"`
- Crit []map[string]any `yac:"crit,omitempty"`
- Pub AV `yac:"pub"`
- KID uuid.UUID `yac:"kid"`
-}
-
-func (tbs *CerTBS) HasCA() (hasCA bool) {
- for _, ku := range tbs.KU {
- if ku == "ca" {
- hasCA = true
- }
- }
- return
-}
-
-type SignedDataLoad struct {
- V any `yac:"v"`
- T string `yac:"t"`
-}
-
-type SignedDataTBS struct {
- V any `yac:"v"`
- Load map[string]any `yac:"load"`
- T string `yac:"t"`
- KID uuid.UUID `yac:"kid"`
-}
-
-type Sig struct {
- Load map[string]any `yac:"load,omitempty"`
- CerLoc []string `yac:"cer-loc,omitempty"`
- Sign AV `yac:"sign"`
- KID uuid.UUID `yac:"kid"`
-}
-
-type SignedData struct {
- Hashes []string `yac:"hash,omitempty"`
- Load SignedDataLoad `yac:"load"`
- Sigs []Sig `yac:"sigs"`
- Cers []SignedData `yac:"certs,omitempty"`
-}
-
-func loadCerFromFile(pth string) (*SignedData, error) {
- data, err := os.ReadFile(pth)
- if err != nil {
- return nil, err
- }
- var sd SignedData
- err = gyac.DecodeToStruct(&sd, data)
- if err != nil {
- return nil, err
- }
- if sd.Load.T != "cer" {
- err = errors.New("non \"cer\" in CA SignedData")
- }
- if len(sd.Sigs) == 0 {
- err = errors.New("no signatures present")
- }
- return &sd, err
-}
+++ /dev/null
-package main
-
-import (
- "bytes"
- "crypto/rand"
- "encoding/json"
- "flag"
- "hash"
- "io"
- "log"
- "os"
- "sort"
- "time"
-
- "github.com/google/uuid"
- "go.cypherpunks.su/gogost/v6/gost3410"
- "go.cypherpunks.su/gogost/v6/gost34112012256"
- "go.cypherpunks.su/gogost/v6/gost34112012512"
- "go.cypherpunks.su/yac/gyac"
-)
-
-const (
- AlgoStreebog256 = "streebog256"
- AlgoGOST3410256A = "gost3410-256A"
- AlgoGOST3410256B = "gost3410-256B"
- AlgoGOST3410256C = "gost3410-256C"
- AlgoGOST3410256D = "gost3410-256D"
- AlgoGOST3410512A = "gost3410-512A"
- AlgoGOST3410512B = "gost3410-512B"
- AlgoGOST3410512C = "gost3410-512C"
-)
-
-func GOST3410CurveByName(name string) (curve *gost3410.Curve) {
- switch name {
- case AlgoGOST3410256A:
- curve = gost3410.CurveIdtc26gost341012256paramSetA()
- case AlgoGOST3410256B:
- curve = gost3410.CurveIdtc26gost341012256paramSetB()
- case AlgoGOST3410256C:
- curve = gost3410.CurveIdtc26gost341012256paramSetC()
- case AlgoGOST3410256D:
- curve = gost3410.CurveIdtc26gost341012256paramSetD()
- case AlgoGOST3410512A:
- curve = gost3410.CurveIdtc26gost341012512paramSetA()
- case AlgoGOST3410512B:
- curve = gost3410.CurveIdtc26gost341012512paramSetB()
- case AlgoGOST3410512C:
- curve = gost3410.CurveIdtc26gost341012512paramSetC()
- }
- return
-}
-
-func HasherByKeyAlgo(a string) hash.Hash {
- switch a {
- case AlgoGOST3410256A, AlgoGOST3410256B, AlgoGOST3410256C, AlgoGOST3410256D:
- return gost34112012256.New()
- case AlgoGOST3410512A, AlgoGOST3410512B, AlgoGOST3410512C:
- return gost34112012512.New()
- default:
- log.Fatal("unsupported CA algorithm")
- }
- return nil
-}
-
-func main() {
- kuMap := make(map[string]struct{})
- flag.Func(
- "ku",
- "Optional key usage, may be specified multiple times",
- func(v string) error {
- kuMap[v] = struct{}{}
- return nil
- },
- )
- sinceRaw := flag.String("since", "",
- "Optional notBefore, \"2006-01-02 15:04:05\" format")
- lifetime := flag.Uint("lifetime", 365,
- "Lifetime of the certificate, days")
- subjRaw := flag.String("subj", `{"CN": "test"}`,
- "JSON map of the subject")
- algo := flag.String("algo", "gost3410-256A", "Public key algorithm")
- issuingCer := flag.String("ca-cer", "",
- "Path to certificate file for issuing with")
- issuingPrv := flag.String("ca-prv", "",
- "Path to private key file for issuing with")
- reuseKey := flag.Bool("reuse-key", false,
- "Reuse the key, do not generate new one")
- prvPath := flag.String("prv", "", "Path to private key file")
- cerPath := flag.String("cer", "", "Path to certificate file")
- verify := flag.Bool("verify", false, "Verify provided -cer with ca-cer")
-
- flag.Parse()
- log.SetFlags(log.Lshortfile)
-
- if *cerPath == "" {
- log.Fatal("no -cer is set")
- }
-
- var ku []string
- for k := range kuMap {
- ku = append(ku, k)
- }
- kuMap = nil
- sort.Sort(gyac.ByLenFirst(ku))
-
- var subj map[string]string
- err := json.Unmarshal([]byte(*subjRaw), &subj)
- if err != nil {
- log.Fatalln("while parsing -subj:", err)
- }
-
- var since time.Time
- if *sinceRaw == "" {
- since = time.Now().UTC().Truncate(time.Second)
- } else {
- since, err = time.Parse(time.DateTime, *sinceRaw)
- if err != nil {
- log.Fatalln("while parsing -since:", err)
- }
- }
- till := since.Add(time.Duration(*lifetime) * 24 * time.Hour)
-
- var caPrv *gost3410.PrivateKey
- var caCerTBS CerTBS
- if *issuingCer != "" {
- var sd *SignedData
- sd, err = loadCerFromFile(*issuingCer)
- if err != nil {
- log.Fatal(err)
- }
- err = gyac.MapToStruct(&caCerTBS, sd.Load.V.(map[string]any))
- if err != nil {
- log.Fatal(err)
- }
- if !*verify {
- if *issuingPrv == "" {
- log.Fatal("no -issuing-key is set")
- }
- caPrv, err = loadPrvFromFile(*issuingPrv)
- if err != nil {
- log.Fatal(err)
- }
- }
- }
-
- if *verify {
- var sd *SignedData
- sd, err = loadCerFromFile(*cerPath)
- if err != nil {
- log.Fatal(err)
- }
- var tbs CerTBS
- err = gyac.MapToStruct(&tbs, sd.Load.V.(map[string]any))
- if err != nil {
- log.Fatal(err)
- }
- sig := sd.Sigs[0]
- if sig.KID != caCerTBS.KID {
- log.Fatal("SKID != AKID")
- }
- if sig.KID != tbs.KID && !caCerTBS.HasCA() {
- log.Fatal("no \"ca\" KU met in CA")
- }
- sdTBS := SignedDataTBS{T: "cer", V: tbs, KID: sig.KID}
- hasher := HasherByKeyAlgo(sig.Sign.A)
- hasher.Write(gyac.EncodeItem(nil, gyac.ItemFromGo(sdTBS)))
- var pub *gost3410.PublicKey
- pub, err = gost3410.NewPublicKeyBE(
- GOST3410CurveByName(caCerTBS.Pub.A),
- caCerTBS.Pub.V,
- )
- if err != nil {
- log.Fatal(err)
- }
- var valid bool
- valid, err = pub.VerifyDigest(hasher.Sum(nil), sig.Sign.V)
- if err != nil {
- log.Fatal(err)
- }
- if !valid {
- os.Exit(1)
- }
- return
- }
-
- if *prvPath == "" {
- log.Fatal("no -prv is set")
- }
-
- curve := GOST3410CurveByName(*algo)
- if curve == nil {
- log.Fatal("unknown -algo specified")
- }
- var prv *gost3410.PrivateKey
- if *reuseKey {
- prv, err = loadPrvFromFile(*prvPath)
- if err != nil {
- log.Fatal(err)
- }
- if prv.C.Name != curve.Name {
- log.Fatal("-algo is not same with private key")
- }
- } else {
- prvRaw := make([]byte, curve.PointSize())
- if _, err = io.ReadFull(rand.Reader, prvRaw); err != nil {
- log.Fatal(err)
- }
- prv, err = gost3410.NewPrivateKeyBE(curve, prvRaw)
- if err != nil {
- log.Fatal(err)
- }
- err = os.WriteFile(*prvPath, gyac.EncodeItem(nil,
- gyac.ItemFromGo(AV{A: *algo, V: prv.RawBE()})), 0o600)
- if err != nil {
- log.Fatal(err)
- }
- }
-
- var pub *gost3410.PublicKey
- pub, err = prv.PublicKey()
- if err != nil {
- log.Fatal(err)
- }
- pubTBS := AV{A: *algo, V: pub.RawBE()}
- var spki uuid.UUID
- {
- hasher := gost34112012256.New()
- hasher.Write(gyac.EncodeItem(nil, gyac.ItemFromGo(pubTBS)))
- spki, err = uuid.NewRandomFromReader(bytes.NewReader(hasher.Sum(nil)))
- if err != nil {
- log.Fatal(err)
- }
- }
- cerTBS := CerTBS{
- KU: ku,
- Exp: []time.Time{since, till},
- KID: spki,
- Subj: subj,
- Pub: pubTBS,
- }
- if caPrv == nil {
- caPrv = prv
- caCerTBS = cerTBS
- } else {
- if !caCerTBS.HasCA() {
- log.Fatal("no \"ca\" KU met in CA")
- }
- }
- sig := Sig{KID: caCerTBS.KID}
- sdTBS := SignedDataTBS{T: "cer", V: cerTBS, KID: sig.KID}
- {
- hasher := HasherByKeyAlgo(caCerTBS.Pub.A)
- hasher.Write(gyac.EncodeItem(nil, gyac.ItemFromGo(sdTBS)))
- sig.Sign = AV{A: caCerTBS.Pub.A}
- sig.Sign.V, err = caPrv.SignDigest(hasher.Sum(nil), rand.Reader)
- if err != nil {
- log.Fatal(err)
- }
- }
- cer := SignedData{Load: SignedDataLoad{T: "cer", V: cerTBS}, Sigs: []Sig{sig}}
- err = os.WriteFile(*cerPath, gyac.EncodeItem(nil, gyac.ItemFromGo(cer)), 0o666)
- if err != nil {
- log.Fatal(err)
- }
-}
TMPDIR=${TMPDIR:-/tmp}
subj='{"CN": "CA", "C": "RU"}'
-test_expect_success "CA generation" "certool \
+test_expect_success "CA generation" "yacertool \
-algo gost3410-512C \
-ku ca \
-prv $TMPDIR/ca.prv -cer $TMPDIR/ca.cer \
-subj '$subj'"
-test_expect_success "CA regeneration" "certool \
+test_expect_success "CA regeneration" "yacertool \
-algo gost3410-512C \
-ku ca \
-prv $TMPDIR/ca.prv -cer $TMPDIR/ca.cer \
-reuse-key \
-subj '$subj'"
-test_expect_success "CA self-signature" "certool \
+test_expect_success "CA self-signature" "yacertool \
-ca-cer $TMPDIR/ca.cer \
-cer $TMPDIR/ca.cer \
-verify"
subj='{"CN": "EE", "C": "RU"}'
-test_expect_success "EE generation" "certool \
+test_expect_success "EE generation" "yacertool \
-algo gost3410-256A \
-ca-prv $TMPDIR/ca.prv -ca-cer $TMPDIR/ca.cer \
-prv $TMPDIR/ee.prv -cer $TMPDIR/ee.cer \
-subj '$subj'"
-test_expect_success "EE chain" "certool \
+test_expect_success "EE chain" "yacertool \
-ca-cer $TMPDIR/ca.cer \
-cer $TMPDIR/ee.cer \
-verify"
-module go.cypherpunks.su/yac/gyac/cmd/certool
+module go.cypherpunks.su/yac/gyac/cmd/yacertool
go 1.22
github.com/google/uuid v1.6.0
go.cypherpunks.su/gogost/v6 v6.0.1
go.cypherpunks.su/yac/gyac v0.0.0-00010101000000-000000000000
+ go.cypherpunks.su/yac/gyac/yacpki v0.0.0-00010101000000-000000000000
)
require (
)
replace go.cypherpunks.su/yac/gyac => ../..
+
+replace go.cypherpunks.su/yac/gyac/yacpki => ../../yacpki
--- /dev/null
+package main
+
+import (
+ "crypto"
+ "crypto/rand"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "sort"
+ "time"
+
+ "go.cypherpunks.su/gogost/v6/gost3410"
+ "go.cypherpunks.su/yac/gyac"
+ "go.cypherpunks.su/yac/gyac/yacpki"
+)
+
+func MustReadFile(p string) []byte {
+ data, err := os.ReadFile(p)
+ if err != nil {
+ panic(fmt.Errorf("read %s: %v", p, err))
+ }
+ return data
+}
+
+func main() {
+ kuMap := make(map[string]struct{})
+ flag.Func(
+ "ku",
+ "Optional key usage, may be specified multiple times",
+ func(v string) error {
+ kuMap[v] = struct{}{}
+ return nil
+ },
+ )
+ sinceRaw := flag.String("since", "",
+ "Optional notBefore, \"2006-01-02 15:04:05\" format")
+ lifetime := flag.Uint("lifetime", 365,
+ "Lifetime of the certificate, days")
+ subjRaw := flag.String("subj", `{"CN": "test"}`,
+ "JSON map of the subject")
+ algo := flag.String("algo", "gost3410-256A", "Public key algorithm")
+ issuingCer := flag.String("ca-cer", "",
+ "Path to certificate file for issuing with")
+ issuingPrv := flag.String("ca-prv", "",
+ "Path to private key file for issuing with")
+ reuseKey := flag.Bool("reuse-key", false,
+ "Reuse the key, do not generate new one")
+ prvPath := flag.String("prv", "", "Path to private key file")
+ cerPath := flag.String("cer", "", "Path to certificate file")
+ verify := flag.Bool("verify", false, "Verify provided -cer with -ca-cer")
+
+ flag.Parse()
+ log.SetFlags(log.Lshortfile)
+
+ if *cerPath == "" {
+ log.Fatal("no -cer is set")
+ }
+
+ var ku []string
+ for k := range kuMap {
+ ku = append(ku, k)
+ }
+ kuMap = nil
+ sort.Sort(gyac.ByLenFirst(ku))
+
+ var subj map[string]string
+ err := json.Unmarshal([]byte(*subjRaw), &subj)
+ if err != nil {
+ log.Fatalln("while parsing -subj:", err)
+ }
+
+ var since time.Time
+ if *sinceRaw == "" {
+ since = time.Now().UTC().Truncate(time.Second)
+ } else {
+ since, err = time.Parse(time.DateTime, *sinceRaw)
+ if err != nil {
+ log.Fatalln("while parsing -since:", err)
+ }
+ }
+ till := since.Add(time.Duration(*lifetime) * 24 * time.Hour)
+
+ var caPrv *gost3410.PrivateKey
+ var caCerLoad *yacpki.CerLoad
+ if *issuingCer != "" {
+ var sd *yacpki.SignedData
+ sd, _, err = yacpki.CerParse(MustReadFile(*issuingCer))
+ if err != nil {
+ log.Fatal(err)
+ }
+ caCerLoad = sd.Load.V.(*yacpki.CerLoad)
+ if !*verify {
+ if *issuingPrv == "" {
+ log.Fatal("no -issuing-key is set")
+ }
+ var signer crypto.Signer
+ signer, err = yacpki.PrvParse(MustReadFile(*issuingPrv))
+ if err != nil {
+ log.Fatal(err)
+ }
+ caPrv = signer.(*gost3410.PrivateKey)
+ }
+ }
+
+ if *verify {
+ var sd *yacpki.SignedData
+ sd, _, err = yacpki.CerParse(MustReadFile(*cerPath))
+ if err != nil {
+ log.Fatal(err)
+ }
+ cerLoad := sd.Load.V.(*yacpki.CerLoad)
+ sig := sd.Sigs[0]
+ if sig.KID != cerLoad.KID && !caCerLoad.HasCA() {
+ log.Fatal("no \"ca\" KU met in CA")
+ }
+ err = sd.CheckSignatureFrom(caCerLoad)
+ if err != nil {
+ if err == yacpki.SigInvalid {
+ os.Exit(1)
+ }
+ log.Fatal(err)
+ }
+ return
+ }
+
+ if *prvPath == "" {
+ log.Fatal("no -prv is set")
+ }
+
+ curve := yacpki.GOST3410CurveByName(*algo)
+ if curve == nil {
+ log.Fatal("unknown -algo specified")
+ }
+ var prv *gost3410.PrivateKey
+ if *reuseKey {
+ var signer crypto.Signer
+ signer, err = yacpki.PrvParse(MustReadFile(*prvPath))
+ if err != nil {
+ log.Fatal(err)
+ }
+ prv = signer.(*gost3410.PrivateKey)
+ if prv.C.Name != curve.Name {
+ log.Fatal("-algo is not same with private key")
+ }
+ } else {
+ prvRaw := make([]byte, curve.PointSize())
+ if _, err = io.ReadFull(rand.Reader, prvRaw); err != nil {
+ log.Fatal(err)
+ }
+ prv, err = gost3410.NewPrivateKeyBE(curve, prvRaw)
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = os.WriteFile(*prvPath, gyac.EncodeItem(nil,
+ gyac.ItemFromGo(yacpki.AV{A: *algo, V: prv.RawBE()})), 0o600)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ var pub *gost3410.PublicKey
+ pub, err = prv.PublicKey()
+ if err != nil {
+ log.Fatal(err)
+ }
+ cerLoad := yacpki.CerLoad{
+ KU: ku,
+ Exp: []time.Time{since, till},
+ Subj: subj,
+ Pub: yacpki.AV{A: *algo, V: pub.RawBE()},
+ }
+ cerLoad.KID = yacpki.KIDFromPub(&cerLoad.Pub)
+ if caPrv == nil {
+ caPrv = prv
+ caCerLoad = &cerLoad
+ } else {
+ if !caCerLoad.HasCA() {
+ log.Fatal("no \"ca\" KU met in CA")
+ }
+ }
+ sd := yacpki.SignedData{Load: yacpki.SignedDataLoad{T: "cer", V: cerLoad}}
+ err = sd.SignWith(caCerLoad, caPrv)
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = os.WriteFile(*cerPath, gyac.EncodeItem(nil, gyac.ItemFromGo(sd)), 0o666)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
return decoder.Decode(src)
}
-func DecodeToStruct(dst any, raw []byte) error {
- item, tail, err := DecodeItem(raw)
+func DecodeToStruct(dst any, raw []byte) (tail []byte, err error) {
+ var item *Item
+ item, tail, err = DecodeItem(raw)
if err != nil {
- return err
- }
- if len(tail) != 0 {
- return errors.New("trailing data")
+ return
}
if ItemType(item.T) != ItemMap {
- return errors.New("non-map")
+ err = errors.New("non-map")
+ return
}
- return MapToStruct(dst, item.ToGo().(map[string]any))
+ err = MapToStruct(dst, item.ToGo().(map[string]any))
+ return
}
--- /dev/null
+package yacpki
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/rand"
+ "errors"
+ "time"
+
+ "github.com/google/uuid"
+ "go.cypherpunks.su/gogost/v6/gost3410"
+ "go.cypherpunks.su/gogost/v6/gost34112012256"
+ "go.cypherpunks.su/yac/gyac"
+)
+
+type AV struct {
+ A string `yac:"a"`
+ V []byte `yac:"v"`
+}
+
+type SignedDataLoad struct {
+ V any `yac:"v"`
+ T string `yac:"t"`
+}
+
+type SignedDataTBS struct {
+ V any `yac:"v"`
+ Load map[string]any `yac:"load"`
+ T string `yac:"t"`
+ KID uuid.UUID `yac:"kid"`
+}
+
+type Sig struct {
+ Load map[string]any `yac:"load,omitempty"`
+ CerLoc []string `yac:"cer-loc,omitempty"`
+ Sign AV `yac:"sign"`
+ KID uuid.UUID `yac:"kid"`
+}
+
+type SignedData struct {
+ Hashes []string `yac:"hash,omitempty"`
+ Load SignedDataLoad `yac:"load"`
+ Sigs []Sig `yac:"sigs"`
+ Cers []SignedData `yac:"certs,omitempty"`
+}
+
+type CerLoad struct {
+ KU []string `yac:"ku,omitempty"`
+ Subj map[string]string `yac:"sub"`
+ Exp []time.Time `yac:"exp"`
+ Crit []map[string]any `yac:"crit,omitempty"`
+ Pub AV `yac:"pub"`
+ KID uuid.UUID `yac:"kid"`
+}
+
+func (tbs *CerLoad) HasCA() (hasCA bool) {
+ for _, ku := range tbs.KU {
+ if ku == "ca" {
+ hasCA = true
+ }
+ }
+ return
+}
+
+func KIDFromPub(pub *AV) (kid uuid.UUID) {
+ hasher := gost34112012256.New()
+ hasher.Write(gyac.EncodeItem(nil, gyac.ItemFromGo(pub)))
+ var err error
+ kid, err = uuid.NewRandomFromReader(bytes.NewReader(hasher.Sum(nil)))
+ if err != nil {
+ panic(err)
+ }
+ return
+}
+
+var SigInvalid = errors.New("signature is invalid")
+
+func (cer *CerLoad) CheckSignature(signed, signature []byte) (err error) {
+ switch cer.Pub.A {
+ case AlgoGOST3410256A, AlgoGOST3410256B, AlgoGOST3410256C, AlgoGOST3410256D, AlgoGOST3410512A, AlgoGOST3410512B, AlgoGOST3410512C:
+ var pub *gost3410.PublicKey
+ pub, err = gost3410.NewPublicKeyBE(GOST3410CurveByName(cer.Pub.A), cer.Pub.V)
+ if err != nil {
+ return
+ }
+ hasher := HasherByKeyAlgo(cer.Pub.A)
+ hasher.Write(signed)
+ var valid bool
+ valid, err = pub.VerifyDigest(hasher.Sum(nil), signature)
+ if !valid {
+ err = SigInvalid
+ }
+ default:
+ err = errors.New("unsupported signature algorithm")
+ }
+ return
+}
+
+func (sd *SignedData) CheckSignatureFrom(parent *CerLoad) (err error) {
+ sig := sd.Sigs[0]
+ if sig.KID != parent.KID {
+ err = errors.New("signer KID != parent KID")
+ return
+ }
+ tbs := SignedDataTBS{T: sd.Load.T, V: sd.Load.V, KID: parent.KID}
+ return parent.CheckSignature(
+ gyac.EncodeItem(nil, gyac.ItemFromGo(tbs)),
+ sig.Sign.V,
+ )
+}
+
+func (sd *SignedData) SignWith(parent *CerLoad, prv crypto.Signer) (err error) {
+ tbs := SignedDataTBS{T: sd.Load.T, V: sd.Load.V, KID: parent.KID}
+ hasher := HasherByKeyAlgo(parent.Pub.A)
+ hasher.Write(gyac.EncodeItem(nil, gyac.ItemFromGo(tbs)))
+ sig := Sig{KID: parent.KID, Sign: AV{A: parent.Pub.A}}
+ sig.Sign.V, err = prv.Sign(rand.Reader, hasher.Sum(nil), nil)
+ if err != nil {
+ return
+ }
+ sd.Sigs = append(sd.Sigs, sig)
+ return
+}
+
+func CerParse(data []byte) (sd *SignedData, tail []byte, err error) {
+ var s SignedData
+ tail, err = gyac.DecodeToStruct(&s, data)
+ if err != nil {
+ return
+ }
+ sd = &s
+ if sd.Load.T != "cer" {
+ err = errors.New("SignedData: not \"cer\" type")
+ return
+ }
+ if len(sd.Sigs) == 0 {
+ err = errors.New("SignedData: no \"sigs\"")
+ return
+ }
+ var tbs CerLoad
+ err = gyac.MapToStruct(&tbs, sd.Load.V.(map[string]any))
+ if err != nil {
+ return
+ }
+ sd.Load.V = &tbs
+ return
+}
--- /dev/null
+package yacpki
+
+import (
+ "hash"
+ "log"
+
+ "go.cypherpunks.su/gogost/v6/gost3410"
+ "go.cypherpunks.su/gogost/v6/gost34112012256"
+ "go.cypherpunks.su/gogost/v6/gost34112012512"
+)
+
+const (
+ AlgoStreebog256 = "streebog256"
+ AlgoGOST3410256A = "gost3410-256A"
+ AlgoGOST3410256B = "gost3410-256B"
+ AlgoGOST3410256C = "gost3410-256C"
+ AlgoGOST3410256D = "gost3410-256D"
+ AlgoGOST3410512A = "gost3410-512A"
+ AlgoGOST3410512B = "gost3410-512B"
+ AlgoGOST3410512C = "gost3410-512C"
+)
+
+func GOST3410CurveByName(name string) (curve *gost3410.Curve) {
+ switch name {
+ case AlgoGOST3410256A:
+ curve = gost3410.CurveIdtc26gost341012256paramSetA()
+ case AlgoGOST3410256B:
+ curve = gost3410.CurveIdtc26gost341012256paramSetB()
+ case AlgoGOST3410256C:
+ curve = gost3410.CurveIdtc26gost341012256paramSetC()
+ case AlgoGOST3410256D:
+ curve = gost3410.CurveIdtc26gost341012256paramSetD()
+ case AlgoGOST3410512A:
+ curve = gost3410.CurveIdtc26gost341012512paramSetA()
+ case AlgoGOST3410512B:
+ curve = gost3410.CurveIdtc26gost341012512paramSetB()
+ case AlgoGOST3410512C:
+ curve = gost3410.CurveIdtc26gost341012512paramSetC()
+ }
+ return
+}
+
+func HasherByKeyAlgo(a string) hash.Hash {
+ switch a {
+ case AlgoGOST3410256A, AlgoGOST3410256B, AlgoGOST3410256C, AlgoGOST3410256D:
+ return gost34112012256.New()
+ case AlgoGOST3410512A, AlgoGOST3410512B, AlgoGOST3410512C:
+ return gost34112012512.New()
+ default:
+ log.Fatal("unsupported CA algorithm")
+ }
+ return nil
+}
--- /dev/null
+module go.cypherpunks.su/yac/gyac/yacpki
+
+go 1.22
+
+require go.cypherpunks.su/tai64n/v3 v3.1.0 // indirect
+
+require (
+ github.com/google/uuid v1.6.0
+ go.cypherpunks.su/gogost/v6 v6.0.1
+ go.cypherpunks.su/yac/gyac v0.0.0-00010101000000-000000000000
+)
+
+require github.com/mitchellh/mapstructure v1.5.0 // indirect
+
+replace go.cypherpunks.su/yac/gyac => ..
--- /dev/null
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+go.cypherpunks.su/gogost/v6 v6.0.1 h1:PFjBnUmfdbx7L5R6hRt/+ZgGwWx45wTIWezFSgmknrs=
+go.cypherpunks.su/gogost/v6 v6.0.1/go.mod h1:qJm0B7KJY4/OD5nYqL10kXY09dUwu2AfwSPu72Otngs=
+go.cypherpunks.su/tai64n/v3 v3.1.0 h1:cdGnanxA5/H3hc37BO9D3h/exChVNEvrPWjTT/kuwQ4=
+go.cypherpunks.su/tai64n/v3 v3.1.0/go.mod h1:zGDFuyiFKJk+iem8lyBaFeCm+MNMOn7RRWy456n1J78=
+golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
-package main
+package yacpki
import (
+ "crypto"
+ "errors"
"fmt"
- "os"
"go.cypherpunks.su/gogost/v6/gost3410"
"go.cypherpunks.su/yac/gyac"
)
-func loadPrvFromFile(pth string) (prv *gost3410.PrivateKey, err error) {
- var data []byte
- data, err = os.ReadFile(pth)
+func PrvParse(data []byte) (prv crypto.Signer, err error) {
+ var av AV
+ var tail []byte
+ tail, err = gyac.DecodeToStruct(&av, data)
if err != nil {
return
}
- var av AV
- err = gyac.DecodeToStruct(&av, data)
- if err != nil {
+ if len(tail) != 0 {
+ err = errors.New("trailing data")
return
}
switch av.A {
)
default:
err = fmt.Errorf("unknown private key algo: %s", av.A)
- return
}
return
}