/
curve.go
123 lines (110 loc) · 2.89 KB
/
curve.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright (c) 2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package cfgutil
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"io"
"time"
"decred.org/dcrwallet/errors"
"github.com/decred/dcrd/certgen"
)
// CurveID specifies a recognized curve through a constant value.
type CurveID int
// Recognized curve IDs.
const (
CurveP256 CurveID = iota
CurveP384
CurveP521
Ed25519
// PreferredCurve is the curve that should be used as the application default.
PreferredCurve = Ed25519
)
// CurveFlag describes a curve and implements the flags.Marshaler and
// Unmarshaler interfaces so it can be used as a config struct field.
type CurveFlag struct {
curveID CurveID
}
// NewCurveFlag creates a CurveFlag with a default curve.
func NewCurveFlag(defaultValue CurveID) *CurveFlag {
return &CurveFlag{defaultValue}
}
// ECDSACurve returns the elliptic curve described by f, or (nil, false) if the
// curve is not one of the elliptic curves suitable for ECDSA.
func (f *CurveFlag) ECDSACurve() (elliptic.Curve, bool) {
switch f.curveID {
case CurveP256:
return elliptic.P256(), true
case CurveP384:
return elliptic.P384(), true
case CurveP521:
return elliptic.P521(), true
default:
return nil, false
}
}
// MarshalFlag satisfies the flags.Marshaler interface.
func (f *CurveFlag) MarshalFlag() (name string, err error) {
switch f.curveID {
case CurveP256:
name = "P-256"
case CurveP384:
name = "P-384"
case CurveP521:
name = "P-521"
case Ed25519:
name = "Ed25519"
default:
err = errors.Errorf("unknown curve ID %v", int(f.curveID))
}
return
}
// UnmarshalFlag satisfies the flags.Unmarshaler interface.
func (f *CurveFlag) UnmarshalFlag(value string) error {
switch value {
case "P-256":
f.curveID = CurveP256
case "P-384":
f.curveID = CurveP384
case "P-521":
f.curveID = CurveP521
case "Ed25519":
f.curveID = Ed25519
default:
return errors.Errorf("unrecognized curve %v", value)
}
return nil
}
func (f *CurveFlag) GenerateKeyPair(rand io.Reader) (pub, priv interface{}, err error) {
if ec, ok := f.ECDSACurve(); ok {
var key *ecdsa.PrivateKey
key, err = ecdsa.GenerateKey(ec, rand)
if err != nil {
return
}
pub, priv = key.Public(), key
return
}
if f.curveID == Ed25519 {
seed := make([]byte, ed25519.SeedSize)
_, err = io.ReadFull(rand, seed)
if err != nil {
return
}
key := ed25519.NewKeyFromSeed(seed)
pub, priv = key.Public(), key
return
}
return nil, nil, errors.New("unknown curve ID")
}
func (f *CurveFlag) CertGen(org string, validUntil time.Time, extraHosts []string) (cert, key []byte, err error) {
if ec, ok := f.ECDSACurve(); ok {
return certgen.NewTLSCertPair(ec, org, validUntil, extraHosts)
}
if f.curveID == Ed25519 {
return certgen.NewEd25519TLSCertPair(org, validUntil, extraHosts)
}
return nil, nil, errors.New("unknown curve ID")
}