1
2
3
4
5
6 package grpc
7
8 import (
9 "fmt"
10 "net"
11 "time"
12
13 "google.golang.org/grpc/codes"
14 "google.golang.org/protobuf/types/known/timestamppb"
15 "gopkg.in/go-jose/go-jose.v2"
16
17 "github.com/letsencrypt/boulder/core"
18 corepb "github.com/letsencrypt/boulder/core/proto"
19 "github.com/letsencrypt/boulder/identifier"
20 "github.com/letsencrypt/boulder/probs"
21 "github.com/letsencrypt/boulder/revocation"
22 sapb "github.com/letsencrypt/boulder/sa/proto"
23 vapb "github.com/letsencrypt/boulder/va/proto"
24 )
25
26 var ErrMissingParameters = CodedError(codes.FailedPrecondition, "required RPC parameter was missing")
27
28
29
30
31 func ProblemDetailsToPB(prob *probs.ProblemDetails) (*corepb.ProblemDetails, error) {
32 if prob == nil {
33
34 return nil, nil
35 }
36 return &corepb.ProblemDetails{
37 ProblemType: string(prob.Type),
38 Detail: prob.Detail,
39 HttpStatus: int32(prob.HTTPStatus),
40 }, nil
41 }
42
43 func PBToProblemDetails(in *corepb.ProblemDetails) (*probs.ProblemDetails, error) {
44 if in == nil {
45
46 return nil, nil
47 }
48 if in.ProblemType == "" || in.Detail == "" {
49 return nil, ErrMissingParameters
50 }
51 prob := &probs.ProblemDetails{
52 Type: probs.ProblemType(in.ProblemType),
53 Detail: in.Detail,
54 }
55 if in.HttpStatus != 0 {
56 prob.HTTPStatus = int(in.HttpStatus)
57 }
58 return prob, nil
59 }
60
61 func ChallengeToPB(challenge core.Challenge) (*corepb.Challenge, error) {
62 prob, err := ProblemDetailsToPB(challenge.Error)
63 if err != nil {
64 return nil, err
65 }
66 recordAry := make([]*corepb.ValidationRecord, len(challenge.ValidationRecord))
67 for i, v := range challenge.ValidationRecord {
68 recordAry[i], err = ValidationRecordToPB(v)
69 if err != nil {
70 return nil, err
71 }
72 }
73
74 var validatedInt int64 = 0
75 validatedTS := timestamppb.New(time.Time{})
76 if challenge.Validated != nil {
77 validatedInt = challenge.Validated.UTC().UnixNano()
78 validatedTS = timestamppb.New(challenge.Validated.UTC())
79 }
80
81 if !validatedTS.IsValid() {
82 return nil, fmt.Errorf("error creating *timestamppb.Timestamp for *corepb.Challenge object")
83 }
84
85 return &corepb.Challenge{
86 Type: string(challenge.Type),
87 Status: string(challenge.Status),
88 Token: challenge.Token,
89 KeyAuthorization: challenge.ProvidedKeyAuthorization,
90 Error: prob,
91 Validationrecords: recordAry,
92 ValidatedNS: validatedInt,
93 Validated: validatedTS,
94 }, nil
95 }
96
97 func PBToChallenge(in *corepb.Challenge) (challenge core.Challenge, err error) {
98 if in == nil {
99 return core.Challenge{}, ErrMissingParameters
100 }
101 if in.Type == "" || in.Status == "" || in.Token == "" {
102 return core.Challenge{}, ErrMissingParameters
103 }
104 var recordAry []core.ValidationRecord
105 if len(in.Validationrecords) > 0 {
106 recordAry = make([]core.ValidationRecord, len(in.Validationrecords))
107 for i, v := range in.Validationrecords {
108 recordAry[i], err = PBToValidationRecord(v)
109 if err != nil {
110 return core.Challenge{}, err
111 }
112 }
113 }
114 prob, err := PBToProblemDetails(in.Error)
115 if err != nil {
116 return core.Challenge{}, err
117 }
118 var validated *time.Time
119 if in.ValidatedNS != 0 {
120 val := time.Unix(0, in.ValidatedNS).UTC()
121 validated = &val
122 }
123 ch := core.Challenge{
124 Type: core.AcmeChallenge(in.Type),
125 Status: core.AcmeStatus(in.Status),
126 Token: in.Token,
127 Error: prob,
128 ValidationRecord: recordAry,
129 Validated: validated,
130 }
131 if in.KeyAuthorization != "" {
132 ch.ProvidedKeyAuthorization = in.KeyAuthorization
133 }
134 return ch, nil
135 }
136
137 func ValidationRecordToPB(record core.ValidationRecord) (*corepb.ValidationRecord, error) {
138 addrs := make([][]byte, len(record.AddressesResolved))
139 addrsTried := make([][]byte, len(record.AddressesTried))
140 var err error
141 for i, v := range record.AddressesResolved {
142 addrs[i] = []byte(v)
143 }
144 for i, v := range record.AddressesTried {
145 addrsTried[i] = []byte(v)
146 }
147 addrUsed, err := record.AddressUsed.MarshalText()
148 if err != nil {
149 return nil, err
150 }
151 return &corepb.ValidationRecord{
152 Hostname: record.Hostname,
153 Port: record.Port,
154 AddressesResolved: addrs,
155 AddressUsed: addrUsed,
156 Url: record.URL,
157 AddressesTried: addrsTried,
158 }, nil
159 }
160
161 func PBToValidationRecord(in *corepb.ValidationRecord) (record core.ValidationRecord, err error) {
162 if in == nil {
163 return core.ValidationRecord{}, ErrMissingParameters
164 }
165 addrs := make([]net.IP, len(in.AddressesResolved))
166 for i, v := range in.AddressesResolved {
167 addrs[i] = net.IP(v)
168 }
169 addrsTried := make([]net.IP, len(in.AddressesTried))
170 for i, v := range in.AddressesTried {
171 addrsTried[i] = net.IP(v)
172 }
173 var addrUsed net.IP
174 err = addrUsed.UnmarshalText(in.AddressUsed)
175 if err != nil {
176 return
177 }
178 return core.ValidationRecord{
179 Hostname: in.Hostname,
180 Port: in.Port,
181 AddressesResolved: addrs,
182 AddressUsed: addrUsed,
183 URL: in.Url,
184 AddressesTried: addrsTried,
185 }, nil
186 }
187
188 func ValidationResultToPB(records []core.ValidationRecord, prob *probs.ProblemDetails) (*vapb.ValidationResult, error) {
189 recordAry := make([]*corepb.ValidationRecord, len(records))
190 var err error
191 for i, v := range records {
192 recordAry[i], err = ValidationRecordToPB(v)
193 if err != nil {
194 return nil, err
195 }
196 }
197 marshalledProbs, err := ProblemDetailsToPB(prob)
198 if err != nil {
199 return nil, err
200 }
201 return &vapb.ValidationResult{
202 Records: recordAry,
203 Problems: marshalledProbs,
204 }, nil
205 }
206
207 func pbToValidationResult(in *vapb.ValidationResult) ([]core.ValidationRecord, *probs.ProblemDetails, error) {
208 if in == nil {
209 return nil, nil, ErrMissingParameters
210 }
211 recordAry := make([]core.ValidationRecord, len(in.Records))
212 var err error
213 for i, v := range in.Records {
214 recordAry[i], err = PBToValidationRecord(v)
215 if err != nil {
216 return nil, nil, err
217 }
218 }
219 prob, err := PBToProblemDetails(in.Problems)
220 if err != nil {
221 return nil, nil, err
222 }
223 return recordAry, prob, nil
224 }
225
226 func RegistrationToPB(reg core.Registration) (*corepb.Registration, error) {
227 keyBytes, err := reg.Key.MarshalJSON()
228 if err != nil {
229 return nil, err
230 }
231 ipBytes, err := reg.InitialIP.MarshalText()
232 if err != nil {
233 return nil, err
234 }
235 var contacts []string
236
237
238
239 contactsPresent := reg.Contact != nil
240 if reg.Contact != nil {
241 contacts = *reg.Contact
242 }
243 var createdAtInt int64 = 0
244 createdAtTS := timestamppb.New(time.Time{})
245 if reg.CreatedAt != nil {
246 createdAtInt = reg.CreatedAt.UTC().UnixNano()
247 createdAtTS = timestamppb.New(reg.CreatedAt.UTC())
248 }
249 if !createdAtTS.IsValid() {
250 return nil, fmt.Errorf("error creating *timestamppb.Timestamp for *corepb.Authorization object")
251 }
252
253 return &corepb.Registration{
254 Id: reg.ID,
255 Key: keyBytes,
256 Contact: contacts,
257 ContactsPresent: contactsPresent,
258 Agreement: reg.Agreement,
259 InitialIP: ipBytes,
260 CreatedAtNS: createdAtInt,
261 CreatedAt: createdAtTS,
262 Status: string(reg.Status),
263 }, nil
264 }
265
266 func PbToRegistration(pb *corepb.Registration) (core.Registration, error) {
267 var key jose.JSONWebKey
268 err := key.UnmarshalJSON(pb.Key)
269 if err != nil {
270 return core.Registration{}, err
271 }
272 var initialIP net.IP
273 err = initialIP.UnmarshalText(pb.InitialIP)
274 if err != nil {
275 return core.Registration{}, err
276 }
277 var createdAt *time.Time
278 if pb.CreatedAtNS != 0 {
279 c := time.Unix(0, pb.CreatedAtNS).UTC()
280 createdAt = &c
281 }
282 var contacts *[]string
283 if pb.ContactsPresent {
284 if len(pb.Contact) != 0 {
285 contacts = &pb.Contact
286 } else {
287
288
289
290
291
292 empty := []string{}
293 contacts = &empty
294 }
295 }
296 return core.Registration{
297 ID: pb.Id,
298 Key: &key,
299 Contact: contacts,
300 Agreement: pb.Agreement,
301 InitialIP: initialIP,
302 CreatedAt: createdAt,
303 Status: core.AcmeStatus(pb.Status),
304 }, nil
305 }
306
307 func AuthzToPB(authz core.Authorization) (*corepb.Authorization, error) {
308 challs := make([]*corepb.Challenge, len(authz.Challenges))
309 for i, c := range authz.Challenges {
310 pbChall, err := ChallengeToPB(c)
311 if err != nil {
312 return nil, err
313 }
314 challs[i] = pbChall
315 }
316 var expiresInt int64 = 0
317 expiresTS := timestamppb.New(time.Time{})
318 if authz.Expires != nil {
319 expiresInt = authz.Expires.UTC().UnixNano()
320 expiresTS = timestamppb.New(authz.Expires.UTC())
321 }
322 if !expiresTS.IsValid() {
323 return nil, fmt.Errorf("error creating *timestamppb.Timestamp for *corepb.Authorization object")
324 }
325
326 return &corepb.Authorization{
327 Id: authz.ID,
328 Identifier: authz.Identifier.Value,
329 RegistrationID: authz.RegistrationID,
330 Status: string(authz.Status),
331 ExpiresNS: expiresInt,
332 Expires: expiresTS,
333 Challenges: challs,
334 }, nil
335 }
336
337 func PBToAuthz(pb *corepb.Authorization) (core.Authorization, error) {
338 challs := make([]core.Challenge, len(pb.Challenges))
339 for i, c := range pb.Challenges {
340 chall, err := PBToChallenge(c)
341 if err != nil {
342 return core.Authorization{}, err
343 }
344 challs[i] = chall
345 }
346 var expires *time.Time
347 if pb.ExpiresNS != 0 {
348 c := time.Unix(0, pb.ExpiresNS).UTC()
349 expires = &c
350 }
351 authz := core.Authorization{
352 ID: pb.Id,
353 Identifier: identifier.ACMEIdentifier{Type: identifier.DNS, Value: pb.Identifier},
354 RegistrationID: pb.RegistrationID,
355 Status: core.AcmeStatus(pb.Status),
356 Expires: expires,
357 Challenges: challs,
358 }
359 return authz, nil
360 }
361
362
363
364
365 func orderValid(order *corepb.Order) bool {
366 return order.Id != 0 && order.CreatedNS != 0 && newOrderValid(order)
367 }
368
369
370
371
372
373
374
375
376 func newOrderValid(order *corepb.Order) bool {
377 return !(order.RegistrationID == 0 || order.ExpiresNS == 0 || len(order.Names) == 0)
378 }
379
380 func CertToPB(cert core.Certificate) *corepb.Certificate {
381 return &corepb.Certificate{
382 RegistrationID: cert.RegistrationID,
383 Serial: cert.Serial,
384 Digest: cert.Digest,
385 Der: cert.DER,
386 IssuedNS: cert.Issued.UnixNano(),
387 Issued: timestamppb.New(cert.Issued),
388 ExpiresNS: cert.Expires.UnixNano(),
389 Expires: timestamppb.New(cert.Expires),
390 }
391 }
392
393 func PBToCert(pb *corepb.Certificate) core.Certificate {
394 return core.Certificate{
395 RegistrationID: pb.RegistrationID,
396 Serial: pb.Serial,
397 Digest: pb.Digest,
398 DER: pb.Der,
399 Issued: time.Unix(0, pb.IssuedNS),
400 Expires: time.Unix(0, pb.ExpiresNS),
401 }
402 }
403
404 func CertStatusToPB(certStatus core.CertificateStatus) *corepb.CertificateStatus {
405 return &corepb.CertificateStatus{
406 Serial: certStatus.Serial,
407 Status: string(certStatus.Status),
408 OcspLastUpdatedNS: certStatus.OCSPLastUpdated.UnixNano(),
409 OcspLastUpdated: timestamppb.New(certStatus.OCSPLastUpdated),
410 RevokedDateNS: certStatus.RevokedDate.UnixNano(),
411 RevokedDate: timestamppb.New(certStatus.RevokedDate),
412 RevokedReason: int64(certStatus.RevokedReason),
413 LastExpirationNagSentNS: certStatus.LastExpirationNagSent.UnixNano(),
414 LastExpirationNagSent: timestamppb.New(certStatus.LastExpirationNagSent),
415 NotAfterNS: certStatus.NotAfter.UnixNano(),
416 NotAfter: timestamppb.New(certStatus.NotAfter),
417 IsExpired: certStatus.IsExpired,
418 IssuerID: certStatus.IssuerNameID,
419 }
420 }
421
422 func PBToCertStatus(pb *corepb.CertificateStatus) core.CertificateStatus {
423 return core.CertificateStatus{
424 Serial: pb.Serial,
425 Status: core.OCSPStatus(pb.Status),
426 OCSPLastUpdated: time.Unix(0, pb.OcspLastUpdatedNS),
427 RevokedDate: time.Unix(0, pb.RevokedDateNS),
428 RevokedReason: revocation.Reason(pb.RevokedReason),
429 LastExpirationNagSent: time.Unix(0, pb.LastExpirationNagSentNS),
430 NotAfter: time.Unix(0, pb.NotAfterNS),
431 IsExpired: pb.IsExpired,
432 IssuerNameID: pb.IssuerID,
433 }
434 }
435
436
437
438 func PBToAuthzMap(pb *sapb.Authorizations) (map[string]*core.Authorization, error) {
439 m := make(map[string]*core.Authorization, len(pb.Authz))
440 for _, v := range pb.Authz {
441 authz, err := PBToAuthz(v.Authz)
442 if err != nil {
443 return nil, err
444 }
445 m[v.Domain] = &authz
446 }
447 return m, nil
448 }
449
View as plain text