/
signCertificate.go
126 lines (115 loc) · 4.27 KB
/
signCertificate.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
package grpc
import (
"context"
"crypto/x509"
"errors"
"fmt"
"regexp"
"time"
"github.com/google/uuid"
"github.com/plgd-dev/hub/v2/certificate-authority/pb"
"github.com/plgd-dev/hub/v2/certificate-authority/store"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func (s *CertificateAuthorityServer) validateRequest(csr []byte) error {
infoData, err := getInfoData(csr)
if err != nil {
return err
}
if infoData.CertificateCommonNameID == s.hubID {
return fmt.Errorf("common name contains same value as hub id(%v)", s.hubID)
}
return nil
}
func (s *CertificateAuthorityServer) updateSigningIdentityCertificateRecord(ctx context.Context, updateSigningRecord *pb.SigningRecord) error {
var found bool
now := time.Now().UnixNano()
err := s.store.LoadSigningRecords(ctx, updateSigningRecord.GetOwner(), &store.SigningRecordsQuery{
CommonNameFilter: []string{updateSigningRecord.GetCommonName()},
}, func(ctx context.Context, iter store.SigningRecordIter) (err error) {
for {
var signingRecord pb.SigningRecord
ok := iter.Next(ctx, &signingRecord)
if !ok {
break
}
if updateSigningRecord.GetPublicKey() != signingRecord.GetPublicKey() && signingRecord.GetCredential().GetValidUntilDate() > now {
return fmt.Errorf("common name %v with different public key fingerprint exist", signingRecord.GetCommonName())
}
found = true
}
return nil
})
if err != nil {
return err
}
if found {
return s.store.UpdateSigningRecord(ctx, updateSigningRecord)
}
return s.store.CreateSigningRecord(ctx, updateSigningRecord)
}
func toSigningRecord(owner string, template *x509.Certificate) (*pb.SigningRecord, error) {
publicKeyRaw, err := x509.MarshalPKIXPublicKey(template.PublicKey)
if err != nil {
return nil, err
}
publicKey := uuid.NewSHA1(uuid.NameSpaceX500, publicKeyRaw).String()
id := uuid.NewSHA1(uuid.NameSpaceX500, append([]byte(template.Subject.CommonName), publicKeyRaw...)).String()
now := time.Now().UnixNano()
m := regexp.MustCompile("uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")
deviceIDCommonName := m.FindString(template.Subject.CommonName)
deviceID := ""
if deviceIDCommonName != "" {
deviceID = deviceIDCommonName[5:]
}
return &pb.SigningRecord{
Id: id,
Owner: owner,
CommonName: template.Subject.CommonName,
PublicKey: publicKey,
CreationDate: now,
DeviceId: deviceID,
Credential: &pb.CredentialStatus{
CertificatePem: "",
Date: now,
ValidUntilDate: template.NotAfter.UnixNano(),
},
}, nil
}
func (s *CertificateAuthorityServer) updateSigningRecord(ctx context.Context, signingRecord *pb.SigningRecord) error {
var checkForIdentity bool
if signingRecord.GetDeviceId() != "" && signingRecord.GetDeviceId() != signingRecord.GetOwner() {
checkForIdentity = true
}
if checkForIdentity {
return s.updateSigningIdentityCertificateRecord(ctx, signingRecord)
}
return s.store.UpdateSigningRecord(ctx, signingRecord)
}
func (s *CertificateAuthorityServer) SignCertificate(ctx context.Context, req *pb.SignCertificateRequest) (*pb.SignCertificateResponse, error) {
const fmtError = "cannot sign certificate: %v"
logger := s.logger.With("csr", string(req.GetCertificateSigningRequest()))
if err := s.validateRequest(req.GetCertificateSigningRequest()); err != nil {
return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, err))
}
signer := s.GetSigner()
if signer == nil {
return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, errors.New("signer is empty")))
}
cert, signingRecord, err := signer.Sign(ctx, req.GetCertificateSigningRequest())
if err != nil {
return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, err))
}
if signingRecord.GetCredential() == nil {
return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, "cannot sign certificate: cannot create signing record"))
}
signingRecord.Credential.CertificatePem = string(cert)
if err := s.updateSigningRecord(ctx, signingRecord); err != nil {
return nil, logger.LogAndReturnError(status.Errorf(codes.InvalidArgument, fmtError, err))
}
logger.With("crt", string(cert)).Debugf("CertificateAuthorityServer.SignCertificate")
return &pb.SignCertificateResponse{
Certificate: cert,
}, nil
}