-
Notifications
You must be signed in to change notification settings - Fork 0
/
cert.go
141 lines (118 loc) · 3.94 KB
/
cert.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package auth
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"math/big"
"time"
"github.com/pborman/uuid"
)
// GetCertificateRequest creates a request to be sent to any authoritative signer, as a PEM-encoded array of bytes.
//
// It can be safely sent via the network.
func GetCertificateRequest(country, organization, unit, mail string, key *rsa.PrivateKey) ([]byte, error) {
template := &x509.CertificateRequest{
Subject: pkix.Name{
Country: []string{country},
Organization: []string{organization},
OrganizationalUnit: []string{unit},
CommonName: mail,
},
}
der, err := x509.CreateCertificateRequest(rand.Reader, template, key)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: der,
}), nil
}
// PEMToCertificateRequest tries to decode a PEM-encoded array of bytes to a certificate request
func PEMToCertificateRequest(data []byte) (*x509.CertificateRequest, error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, errors.New("Couldn't decode the PEM data as a x509 Certificate request")
}
return x509.ParseCertificateRequest(block.Bytes)
}
// GetCertificate builds a certificate from a certificate request and an authoritative certificate (CA), as a PEM-encoded array of bytes.
// This function assumes that the identity of the signee is valid.
//
// The serial has to be unique and positive.
//
// The generated certificate can safely be distributed to unknown actors.
func GetCertificate(days int, serial uint64, req *x509.CertificateRequest, parent *x509.Certificate, key *rsa.PrivateKey) ([]byte, error) {
template := &x509.Certificate{
SerialNumber: new(big.Int).SetUint64(serial),
Subject: req.Subject,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 0, days),
IsCA: false,
DNSNames: []string{"*"},
}
der, err := x509.CreateCertificate(rand.Reader, template, parent, req.PublicKey, key)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: der,
}), nil
}
// GetSelfSignedCertificate builds a CA certificate from a private key, as a PEM-encoded array of bytes.
//
// The serial has to be unique and positive.
//
// The generated certificate should be distributed to any other actor in the network under this CA.
func GetSelfSignedCertificate(days int, serial uint64, country, organization, unit, cn string, key *rsa.PrivateKey) ([]byte, error) {
template := &x509.Certificate{
SerialNumber: new(big.Int).SetUint64(serial),
Subject: pkix.Name{
Country: []string{country},
Organization: []string{organization},
OrganizationalUnit: []string{unit},
CommonName: cn,
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 0, days),
BasicConstraintsValid: true,
IsCA: true,
DNSNames: []string{"*"},
}
der, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: der,
}), nil
}
// PEMToCertificate tries to decode a PEM-encoded array of bytes to a certificate
func PEMToCertificate(data []byte) (*x509.Certificate, error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, fmt.Errorf("Data is not a valid pem-encoding")
}
return x509.ParseCertificate(block.Bytes)
}
// GetCertificateHash returns the SHA512 hash of a certificate
func GetCertificateHash(cert *x509.Certificate) []byte {
h := sha512.Sum512(cert.Raw)
return h[:]
}
// GenerateUID generates a unique identifier as a uint64
func GenerateUID() uint64 {
// Generating and converting the uuid to fit our needs: an 8 bytes unsigned integer
uuid := uuid.NewRandom()
var slice []byte
slice = uuid[:8]
// TODO: improve this conversion method/need
return new(big.Int).SetBytes(slice).Uint64()
}