// IssueCertificate signs a certificate signing request if // authorized. This function will block until the requst is completed // by the ACME server. func (a *ClientAccount) IssueCertificate(csr []byte) (*Certificate, error) { d, err := a.directory() if err != nil { return nil, err } cbs, resp, err := protocol.PostCertificateIssuance(a.http, d.NewCert, &protocol.CertificateIssuance{ Resource: protocol.ResourceNewCert, CSR: protocol.DERData(csr), }) if err != nil { return nil, err } if resp.StatusCode != http.StatusCreated { return nil, fmt.Errorf("issue certificate: unexpected HTTP status: %s", resp.Status) } uri, err := contentLocation(resp) // ACME Spec Sec. 6.6 says servers SHOULD provide Content-Location. // Boulder does not, so fall back to Location (which is not stable). if err == http.ErrNoLocation { uri, err = resp.Location() } if err != nil { return nil, err } if len(cbs) != 0 { return &Certificate{ Bytes: cbs, URI: uri.String(), IssuerURIs: links(resp, "up"), }, err } ra, _ := retryAfter(resp.Header, 1*time.Second) time.Sleep(ra) return a.Certificate(uri.String()) }
// RevokeCertificate requests a revocation. The given cert should be // exactly the same as returned by IssueCertificate. func (a *ClientAccount) RevokeCertificate(cert []byte) error { d, err := a.directory() if err != nil { return err } req := &protocol.Certificate{ Resource: protocol.ResourceRevokeCert, Certificate: protocol.DERData(cert), } resp, err := protocol.PostCertificateRevocation(a.http, d.RevokeCert, req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("revoke certificate: unexpected HTTP status: %s", resp.Status) } return nil }
func TestWriteChallenge(t *testing.T) { tsts := []struct { in protocol.Challenge want []string err error }{ { in: &protocol.DNS01Challenge{ Type: protocol.ChallengeDNS01, Token: "token", }, want: []string{"dns-01", "token", "token.luhDRvWTmOMLRwM2gMkTDdC88jVeIXo9Hm1r_Q6W41Y"}, }, { in: &protocol.HTTP01Challenge{ Type: protocol.ChallengeHTTP01, Token: "token", }, want: []string{"http-01", "token", "token.luhDRvWTmOMLRwM2gMkTDdC88jVeIXo9Hm1r_Q6W41Y"}, }, { in: &protocol.Possession01Challenge{ Type: protocol.ChallengePossession01, Certs: []protocol.DERData{protocol.DERData("hello"), protocol.DERData("world")}, }, want: []string{"proofOfPossession-01", "aGVsbG8=", "d29ybGQ="}, }, { in: &protocol.TLSSNI01Challenge{ Type: protocol.ChallengeTLSSNI01, Token: "token", N: 2, }, want: []string{ "tls-sni-01", "token", "token.luhDRvWTmOMLRwM2gMkTDdC88jVeIXo9Hm1r_Q6W41Y", "c6b5052764ef075d8eafa41868fb8e88.1ef567ba3f4a0721a8dd63153c8a079e.acme.invalid", "e3e1b3a270c6b5566cb36f9ca4f0939c.af758bfb4ced915161127327053fbbdb.acme.invalid", }, }, { in: &protocol.GenericChallenge{}, err: fmt.Errorf("unknown challenge type"), }, } for _, tst := range tsts { var b bytes.Buffer cw := csv.NewWriter(&b) if err := writeChallenge(cw, tst.in, testJWK); !matchError(err, tst.err) { t.Errorf("writeChallenge(%v) err: got %v, want prefix %v", tst.in, err, tst.err) } cw.Flush() cr := csv.NewReader(&b) got, err := cr.Read() if err != io.EOF && err != nil { t.Fatalf("cw.Read failed: %v", err) } if !reflect.DeepEqual(got, tst.want) { t.Errorf("writeChallenge(%v): got %s, want %s", tst.in, got, tst.want) } } }