Merge pull request #65 from letsencrypt/vendorize
Vendorize all dependencies with godep.
This commit is contained in:
		
						commit
						e077548886
					
				| 
						 | 
				
			
			@ -11,6 +11,9 @@ _test
 | 
			
		|||
*.[568vq]
 | 
			
		||||
[568vq].out
 | 
			
		||||
 | 
			
		||||
# Vim swap files
 | 
			
		||||
*.sw?
 | 
			
		||||
 | 
			
		||||
*.cgo1.go
 | 
			
		||||
*.cgo2.c
 | 
			
		||||
_cgo_defun.c
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								.travis.yml
								
								
								
								
							
							
						
						
									
										18
									
								
								.travis.yml
								
								
								
								
							| 
						 | 
				
			
			@ -13,21 +13,5 @@ before_install:
 | 
			
		|||
  - go get github.com/mattn/goveralls
 | 
			
		||||
  - go get github.com/modocache/gover
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - go get -t -v -tags "pkcs11" ./...
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - go vet -x ./...
 | 
			
		||||
  - $HOME/gopath/bin/golint ./...
 | 
			
		||||
  - go test -covermode=count -coverprofile=analysis.coverprofile ./analysis/
 | 
			
		||||
  - go test -covermode=count -coverprofile=ca.coverprofile ./ca/
 | 
			
		||||
  - go test -covermode=count -coverprofile=core.coverprofile ./core/
 | 
			
		||||
  - go test -covermode=count -coverprofile=log.coverprofile ./log/
 | 
			
		||||
  - go test -covermode=count -coverprofile=ra.coverprofile ./ra/
 | 
			
		||||
  - go test -covermode=count -coverprofile=rpc.coverprofile ./rpc/
 | 
			
		||||
  - go test -covermode=count -coverprofile=sa.coverprofile ./sa/
 | 
			
		||||
  - go test -covermode=count -coverprofile=test.coverprofile ./test/
 | 
			
		||||
  - go test -covermode=count -coverprofile=va.coverprofile ./va/
 | 
			
		||||
  - go test -covermode=count -coverprofile=wfe.coverprofile ./wfe/
 | 
			
		||||
  - $HOME/gopath/bin/gover
 | 
			
		||||
  - $HOME/gopath/bin/goveralls -coverprofile=gover.coverprofile -service=travis-ci
 | 
			
		||||
  - bash test.sh
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								Dockerfile
								
								
								
								
							
							
						
						
									
										10
									
								
								Dockerfile
								
								
								
								
							| 
						 | 
				
			
			@ -8,16 +8,6 @@ EXPOSE 4000
 | 
			
		|||
# Assume the configuration is in /etc/boulder
 | 
			
		||||
ENV BOULDER_CONFIG=/boulder/config.json
 | 
			
		||||
 | 
			
		||||
# Load the dependencies
 | 
			
		||||
RUN go-wrapper download github.com/bifurcation/gose && \
 | 
			
		||||
    go-wrapper download github.com/codegangsta/cli && \
 | 
			
		||||
    go-wrapper download github.com/streadway/amqp && \
 | 
			
		||||
    go-wrapper download github.com/mattn/go-sqlite3 && \
 | 
			
		||||
    go-wrapper download github.com/go-sql-driver/mysql && \
 | 
			
		||||
    go-wrapper download github.com/cloudflare/cfssl/auth && \
 | 
			
		||||
    go-wrapper download github.com/cloudflare/cfssl/config && \
 | 
			
		||||
    go-wrapper download github.com/cloudflare/cfssl/signer
 | 
			
		||||
 | 
			
		||||
# Copy in the Boulder sources
 | 
			
		||||
RUN mkdir -p /go/src/github.com/letsencrypt/boulder
 | 
			
		||||
COPY . /go/src/github.com/letsencrypt/boulder
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
{
 | 
			
		||||
	"ImportPath": "github.com/letsencrypt/boulder",
 | 
			
		||||
	"GoVersion": "go1.4.1",
 | 
			
		||||
	"Packages": [
 | 
			
		||||
		"./..."
 | 
			
		||||
	],
 | 
			
		||||
	"Deps": [
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/api",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/auth",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/config",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/csr",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/errors",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/helpers",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/log",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/cloudflare/cfssl/signer",
 | 
			
		||||
			"Rev": "1415724f395ffd7aa29176066765cabc68193453"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/codegangsta/cli",
 | 
			
		||||
			"Comment": "1.2.0-64-ge1712f3",
 | 
			
		||||
			"Rev": "e1712f381785e32046927f64a7c86fe569203196"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/go-sql-driver/mysql",
 | 
			
		||||
			"Comment": "v1.2-88-ga197e5d",
 | 
			
		||||
			"Rev": "a197e5d40516f2e9f74dcee085a5f2d4604e94df"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/mattn/go-sqlite3",
 | 
			
		||||
			"Rev": "308067797b0fcce4ca06362580dc6db77c1bfeda"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/streadway/amqp",
 | 
			
		||||
			"Rev": "150b7f24d6ad507e6026c13d85ce1f1391ac7400"
 | 
			
		||||
		}
 | 
			
		||||
	]
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
This directory tree is generated automatically by godep.
 | 
			
		||||
 | 
			
		||||
Please do not edit.
 | 
			
		||||
 | 
			
		||||
See https://github.com/tools/godep for more information.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
/pkg
 | 
			
		||||
/bin
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,204 @@
 | 
			
		|||
// Package api implements an HTTP-based API and server for CF-SSL.
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Handler is an interface providing a generic mechanism for handling HTTP requests.
 | 
			
		||||
type Handler interface {
 | 
			
		||||
	Handle(w http.ResponseWriter, r *http.Request) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HTTPHandler is a wrapper that encapsulates Handler interface as http.Handler.
 | 
			
		||||
// HttpHandler also enforces that the Handler only responds to requests with registered HTTP method.
 | 
			
		||||
type HTTPHandler struct {
 | 
			
		||||
	Handler        // CFSSL handler
 | 
			
		||||
	Method  string // The assoicated HTTP method
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HandlerFunc is similar to the http.HandlerFunc type; it serves as
 | 
			
		||||
// an adapter allowing the use of ordinary functions as Handlers. If
 | 
			
		||||
// f is a function with the appropriate signature, HandlerFunc(f) is a
 | 
			
		||||
// Handler object that calls f.
 | 
			
		||||
type HandlerFunc func(http.ResponseWriter, *http.Request) error
 | 
			
		||||
 | 
			
		||||
// Handle calls f(w, r)
 | 
			
		||||
func (f HandlerFunc) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	return f(w, r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handleError is the centralised error handling and reporting.
 | 
			
		||||
func handleError(w http.ResponseWriter, err error) (code int) {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return http.StatusOK
 | 
			
		||||
	}
 | 
			
		||||
	msg := err.Error()
 | 
			
		||||
	httpCode := http.StatusInternalServerError
 | 
			
		||||
 | 
			
		||||
	// If it is recognized as HttpError emitted from cf-ssl,
 | 
			
		||||
	// we rewrite the status code accordingly. If it is a
 | 
			
		||||
	// cf-ssl error, set the http status to StatusBadRequest
 | 
			
		||||
	switch err := err.(type) {
 | 
			
		||||
	case *errors.HTTPError:
 | 
			
		||||
		httpCode = err.StatusCode
 | 
			
		||||
		code = err.StatusCode
 | 
			
		||||
	case *errors.Error:
 | 
			
		||||
		httpCode = http.StatusBadRequest
 | 
			
		||||
		code = err.ErrorCode
 | 
			
		||||
		msg = err.Message
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	response := NewErrorResponse(msg, code)
 | 
			
		||||
	jsonMessage, err := json.Marshal(response)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("Failed to marshal JSON: %v", err)
 | 
			
		||||
	} else {
 | 
			
		||||
		msg = string(jsonMessage)
 | 
			
		||||
	}
 | 
			
		||||
	http.Error(w, msg, httpCode)
 | 
			
		||||
	return code
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP encapsulates the call to underlying Handler to handle the request
 | 
			
		||||
// and return the response with proper HTTP status code
 | 
			
		||||
func (h HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	var err error
 | 
			
		||||
	// Throw 405 when requested with an unsupported verb.
 | 
			
		||||
	if r.Method != h.Method {
 | 
			
		||||
		err = errors.NewMethodNotAllowed(r.Method)
 | 
			
		||||
	} else {
 | 
			
		||||
		err = h.Handle(w, r)
 | 
			
		||||
	}
 | 
			
		||||
	status := handleError(w, err)
 | 
			
		||||
	log.Infof("%s - \"%s %s\" %d", r.RemoteAddr, r.Method, r.URL, status)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readRequestBlob takes a JSON-blob-encoded response body in the form
 | 
			
		||||
// map[string]string and returns it, the list of keywords presented,
 | 
			
		||||
// and any error that occurred.
 | 
			
		||||
func readRequestBlob(r *http.Request) (map[string]string, error) {
 | 
			
		||||
	var blob map[string]string
 | 
			
		||||
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	r.Body.Close()
 | 
			
		||||
 | 
			
		||||
	err = json.Unmarshal(body, &blob)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return blob, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ProcessRequestOneOf reads a JSON blob for the request and makes
 | 
			
		||||
// sure it contains one of a set of keywords. For example, a request
 | 
			
		||||
// might have the ('foo' && 'bar') keys, OR it might have the 'baz'
 | 
			
		||||
// key.  In either case, we want to accept the request; however, if
 | 
			
		||||
// none of these sets shows up, the request is a bad request, and it
 | 
			
		||||
// should be returned.
 | 
			
		||||
func ProcessRequestOneOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
 | 
			
		||||
	blob, err := readRequestBlob(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var matched []string
 | 
			
		||||
	for _, set := range keywordSets {
 | 
			
		||||
		if matchKeywords(blob, set) {
 | 
			
		||||
			if matched != nil {
 | 
			
		||||
				return nil, nil, errors.NewBadRequestString("mismatched parameters")
 | 
			
		||||
			}
 | 
			
		||||
			matched = set
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if matched == nil {
 | 
			
		||||
		return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
 | 
			
		||||
	}
 | 
			
		||||
	return blob, matched, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ProcessRequestFirstMatchOf reads a JSON blob for the request and returns
 | 
			
		||||
// the first match of a set of keywords. For example, a request
 | 
			
		||||
// might have one of the following combinations: (foo=1, bar=2), (foo=1), and (bar=2)
 | 
			
		||||
// By giving a specific ordering of those combinations, we could decide how to accept
 | 
			
		||||
// the request.
 | 
			
		||||
func ProcessRequestFirstMatchOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
 | 
			
		||||
	blob, err := readRequestBlob(r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, set := range keywordSets {
 | 
			
		||||
		if matchKeywords(blob, set) {
 | 
			
		||||
			return blob, set, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func matchKeywords(blob map[string]string, keywords []string) bool {
 | 
			
		||||
	for _, keyword := range keywords {
 | 
			
		||||
		if _, ok := blob[keyword]; !ok {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ResponseMessage implements the standard for response errors and
 | 
			
		||||
// messages. A message has a code and a string message.
 | 
			
		||||
type ResponseMessage struct {
 | 
			
		||||
	Code    int    `json:"code"`
 | 
			
		||||
	Message string `json:"message"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Response implements the CloudFlare standard for API
 | 
			
		||||
// responses. CFSSL does not currently use the messages field, but it
 | 
			
		||||
// is provided for compatability.
 | 
			
		||||
type Response struct {
 | 
			
		||||
	Success  bool              `json:"success"`
 | 
			
		||||
	Result   interface{}       `json:"result"`
 | 
			
		||||
	Errors   []ResponseMessage `json:"errors"`
 | 
			
		||||
	Messages []ResponseMessage `json:"messages"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSuccessResponse is a shortcut for creating new successul API
 | 
			
		||||
// responses. CFSSL does not use the messages field, but it is
 | 
			
		||||
// provided to conform to the CloudFlare standard.
 | 
			
		||||
func NewSuccessResponse(result interface{}) Response {
 | 
			
		||||
	return Response{
 | 
			
		||||
		Success:  true,
 | 
			
		||||
		Result:   result,
 | 
			
		||||
		Errors:   []ResponseMessage{},
 | 
			
		||||
		Messages: []ResponseMessage{},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewErrorResponse is a shortcut for creating an error response for a
 | 
			
		||||
// single error.
 | 
			
		||||
func NewErrorResponse(message string, code int) Response {
 | 
			
		||||
	return Response{
 | 
			
		||||
		Success:  false,
 | 
			
		||||
		Result:   nil,
 | 
			
		||||
		Errors:   []ResponseMessage{{code, message}},
 | 
			
		||||
		Messages: []ResponseMessage{},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SendResponse builds a response from the result, sets the JSON
 | 
			
		||||
// header, and writes to the http.ResponseWriter.
 | 
			
		||||
func SendResponse(w http.ResponseWriter, result interface{}) error {
 | 
			
		||||
	response := NewSuccessResponse(result)
 | 
			
		||||
	w.Header().Set("Content-Type", "application/json")
 | 
			
		||||
	enc := json.NewEncoder(w)
 | 
			
		||||
	err := enc.Encode(response)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/api_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										220
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/api_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,220 @@
 | 
			
		|||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ty   = "Thank you!"
 | 
			
		||||
	deny = "That's not true!"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func simpleHandle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	_, _, err := ProcessRequestOneOf(r, [][]string{
 | 
			
		||||
		[]string{"compliment"},
 | 
			
		||||
		[]string{"critique"},
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return SendResponse(w, ty)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cleverHandle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	_, matched, err := ProcessRequestFirstMatchOf(r, [][]string{
 | 
			
		||||
		[]string{"compliment"},
 | 
			
		||||
		[]string{"critique"},
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if matched[0] == "critique" {
 | 
			
		||||
		return SendResponse(w, deny)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return SendResponse(w, ty)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func post(t *testing.T, obj map[string]interface{}, ts *httptest.Server) (resp *http.Response, body []byte) {
 | 
			
		||||
	blob, err := json.Marshal(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	body, err = ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func get(t *testing.T, ts *httptest.Server) (resp *http.Response, body []byte) {
 | 
			
		||||
	resp, err := http.Get(ts.URL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body, err = ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRigidHandle(t *testing.T) {
 | 
			
		||||
	ts := httptest.NewServer(HTTPHandler{Handler: HandlerFunc(simpleHandle), Method: "POST"})
 | 
			
		||||
	defer ts.Close()
 | 
			
		||||
 | 
			
		||||
	// Response to compliment
 | 
			
		||||
	obj := map[string]interface{}{}
 | 
			
		||||
	obj["compliment"] = "it's good"
 | 
			
		||||
	resp, body := post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		t.Errorf("Test expected 200, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message := new(Response)
 | 
			
		||||
	err := json.Unmarshal(body, message)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("failed to read response body: %v", err)
 | 
			
		||||
		t.Fatal("returned:", message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.Result != ty {
 | 
			
		||||
		t.Fatal("Wrong response")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Response to critique
 | 
			
		||||
	obj = map[string]interface{}{}
 | 
			
		||||
	obj["critique"] = "it's bad"
 | 
			
		||||
	resp, body = post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		t.Errorf("Test expected 200, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message = new(Response)
 | 
			
		||||
	err = json.Unmarshal(body, message)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("failed to read response body: %v", err)
 | 
			
		||||
		t.Fatal("returned:", message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.Result != ty {
 | 
			
		||||
		t.Fatal("Wrong response")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// reject mixed review
 | 
			
		||||
	obj = map[string]interface{}{}
 | 
			
		||||
	obj["critique"] = "it's OK"
 | 
			
		||||
	obj["compliment"] = "it's not bad"
 | 
			
		||||
	resp, body = post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusBadRequest {
 | 
			
		||||
		t.Errorf("Test expected 400, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// reject empty review
 | 
			
		||||
	obj = map[string]interface{}{}
 | 
			
		||||
	resp, body = post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusBadRequest {
 | 
			
		||||
		t.Errorf("Test expected 400, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// reject GET
 | 
			
		||||
	resp, body = get(t, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Errorf("Test expected 405, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCleverHandle(t *testing.T) {
 | 
			
		||||
	ts := httptest.NewServer(HTTPHandler{Handler: HandlerFunc(cleverHandle), Method: "POST"})
 | 
			
		||||
	defer ts.Close()
 | 
			
		||||
 | 
			
		||||
	// Response ty to compliment
 | 
			
		||||
	obj := map[string]interface{}{}
 | 
			
		||||
	obj["compliment"] = "it's good"
 | 
			
		||||
	resp, body := post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		t.Errorf("Test expected 200, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message := new(Response)
 | 
			
		||||
	err := json.Unmarshal(body, message)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("failed to read response body: %v", err)
 | 
			
		||||
		t.Fatal("returned:", message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.Result != ty {
 | 
			
		||||
		t.Fatal("Wrong response")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Response deny to critique
 | 
			
		||||
	obj = map[string]interface{}{}
 | 
			
		||||
	obj["critique"] = "it's bad"
 | 
			
		||||
	resp, body = post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		t.Errorf("Test expected 200, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message = new(Response)
 | 
			
		||||
	err = json.Unmarshal(body, message)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("failed to read response body: %v", err)
 | 
			
		||||
		t.Fatal("returned:", message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.Result != deny {
 | 
			
		||||
		t.Fatal("Wrong response")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Be polite to mixed review
 | 
			
		||||
	obj = map[string]interface{}{}
 | 
			
		||||
	obj["critique"] = "it's OK"
 | 
			
		||||
	obj["compliment"] = "it's not bad"
 | 
			
		||||
	resp, body = post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	message = new(Response)
 | 
			
		||||
	err = json.Unmarshal(body, message)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("failed to read response body: %v", err)
 | 
			
		||||
		t.Fatal("returned:", message)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if message.Result != ty {
 | 
			
		||||
		t.Fatal("Wrong response")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// reject empty review
 | 
			
		||||
	obj = map[string]interface{}{}
 | 
			
		||||
	resp, body = post(t, obj, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusBadRequest {
 | 
			
		||||
		t.Errorf("Test expected 400, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// reject GET
 | 
			
		||||
	resp, body = get(t, ts)
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Errorf("Test expected 405, have %d", resp.StatusCode)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/bundle/bundle.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										90
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/bundle/bundle.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
package bundle
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/cloudflare/cfssl/bundler"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Handler accepts requests for either remote or uploaded
 | 
			
		||||
// certificates to be bundled, and returns a certificate bundle (or
 | 
			
		||||
// error).
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	bundler *bundler.Bundler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a new bundler that uses the root bundle and
 | 
			
		||||
// intermediate bundle in the trust chain.
 | 
			
		||||
func NewHandler(caBundleFile, intBundleFile string) (http.Handler, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	b := new(Handler)
 | 
			
		||||
	if b.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Info("bundler API ready")
 | 
			
		||||
	return api.HTTPHandler{Handler: b, Method: "POST"}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle implements an http.Handler interface for the bundle handler.
 | 
			
		||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	blob, matched, err := api.ProcessRequestFirstMatchOf(r,
 | 
			
		||||
		[][]string{
 | 
			
		||||
			[]string{"certificate"},
 | 
			
		||||
			[]string{"domain"},
 | 
			
		||||
		})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("invalid request: %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	flavor := blob["flavor"]
 | 
			
		||||
	bf := bundler.Ubiquitous
 | 
			
		||||
	if flavor != "" {
 | 
			
		||||
		bf = bundler.BundleFlavor(flavor)
 | 
			
		||||
	}
 | 
			
		||||
	log.Infof("request for flavor %v", bf)
 | 
			
		||||
 | 
			
		||||
	var result *bundler.Bundle
 | 
			
		||||
	switch matched[0] {
 | 
			
		||||
	case "domain":
 | 
			
		||||
		bundle, err := h.bundler.BundleFromRemote(blob["domain"], blob["ip"], bf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Warningf("couldn't bundle from remote: %v", err)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		result = bundle
 | 
			
		||||
	case "certificate":
 | 
			
		||||
		bundle, err := h.bundler.BundleFromPEM([]byte(blob["certificate"]), []byte(blob["private_key"]), bf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Warning("bad PEM certifcate or private key")
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		serverName := blob["domain"]
 | 
			
		||||
		ip := blob["ip"]
 | 
			
		||||
 | 
			
		||||
		if serverName != "" {
 | 
			
		||||
			err := bundle.Cert.VerifyHostname(serverName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ip != "" {
 | 
			
		||||
			err := bundle.Cert.VerifyHostname(ip)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		result = bundle
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("wrote response")
 | 
			
		||||
	return api.SendResponse(w, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										214
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/bundle/bundle_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										214
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/bundle/bundle_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,214 @@
 | 
			
		|||
package bundle
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testCaBundleFile     = "../testdata/ca-bundle.pem"
 | 
			
		||||
	testIntBundleFile    = "../testdata/int-bundle.pem"
 | 
			
		||||
	testLeafCertFile     = "../testdata/leaf.pem"
 | 
			
		||||
	testLeafKeyFile      = "../testdata/leaf.key"
 | 
			
		||||
	testLeafWrongKeyFile = "../testdata/leaf.badkey"
 | 
			
		||||
	testBrokenCertFile   = "../testdata/broken.pem"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newTestHandler(t *testing.T) (h http.Handler) {
 | 
			
		||||
	h, err := NewHandler(testCaBundleFile, testIntBundleFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newBundleServer(t *testing.T) *httptest.Server {
 | 
			
		||||
	ts := httptest.NewServer(newTestHandler(t))
 | 
			
		||||
	return ts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testBundleFile(t *testing.T, domain, ip, certFile, keyFile, flavor string) (resp *http.Response, body []byte) {
 | 
			
		||||
	ts := newBundleServer(t)
 | 
			
		||||
	defer ts.Close()
 | 
			
		||||
	var certPEM, keyPEM []byte
 | 
			
		||||
	if certFile != "" {
 | 
			
		||||
		var err error
 | 
			
		||||
		certPEM, err = ioutil.ReadFile(certFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if keyFile != "" {
 | 
			
		||||
		var err error
 | 
			
		||||
		keyPEM, err = ioutil.ReadFile(keyFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	obj := map[string]string{"flavor": flavor}
 | 
			
		||||
	if len(domain) > 0 {
 | 
			
		||||
		obj["domain"] = domain
 | 
			
		||||
	}
 | 
			
		||||
	if len(ip) > 0 {
 | 
			
		||||
		obj["ip"] = ip
 | 
			
		||||
	}
 | 
			
		||||
	if len(certPEM) > 0 {
 | 
			
		||||
		obj["certificate"] = string(certPEM)
 | 
			
		||||
	}
 | 
			
		||||
	if len(keyPEM) > 0 {
 | 
			
		||||
		obj["private_key"] = string(keyPEM)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blob, err := json.Marshal(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	body, err = ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewHandler(t *testing.T) {
 | 
			
		||||
	newTestHandler(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bundleTest struct {
 | 
			
		||||
	Domain             string
 | 
			
		||||
	IP                 string
 | 
			
		||||
	CertFile           string
 | 
			
		||||
	KeyFile            string
 | 
			
		||||
	Flavor             string
 | 
			
		||||
	ExpectedHTTPStatus int
 | 
			
		||||
	ExpectedSuccess    bool
 | 
			
		||||
	ExpectedErrorCode  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var bundleTests = []bundleTest{
 | 
			
		||||
	// Test bundling with certificate
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusOK,
 | 
			
		||||
		ExpectedSuccess:    true,
 | 
			
		||||
		ExpectedErrorCode:  0,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		Flavor:             "ubiquitous",
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusOK,
 | 
			
		||||
		ExpectedSuccess:    true,
 | 
			
		||||
		ExpectedErrorCode:  0,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		Flavor:             "optimal",
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusOK,
 | 
			
		||||
		ExpectedSuccess:    true,
 | 
			
		||||
		ExpectedErrorCode:  0,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		KeyFile:            testLeafKeyFile,
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusOK,
 | 
			
		||||
		ExpectedSuccess:    true,
 | 
			
		||||
		ExpectedErrorCode:  0,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		Domain:             "cfssl-leaf.com",
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusOK,
 | 
			
		||||
		ExpectedSuccess:    true,
 | 
			
		||||
		ExpectedErrorCode:  0,
 | 
			
		||||
	},
 | 
			
		||||
	// Test bundling with remote domain
 | 
			
		||||
	{
 | 
			
		||||
		Domain:             "google.com",
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusBadRequest,
 | 
			
		||||
		ExpectedSuccess:    false,
 | 
			
		||||
		ExpectedErrorCode:  1220,
 | 
			
		||||
	},
 | 
			
		||||
	// Error testing.
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		KeyFile:            testLeafWrongKeyFile,
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusBadRequest,
 | 
			
		||||
		ExpectedSuccess:    false,
 | 
			
		||||
		ExpectedErrorCode:  2300,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		// no input parameter is specified
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusBadRequest,
 | 
			
		||||
		ExpectedSuccess:    false,
 | 
			
		||||
		ExpectedErrorCode:  http.StatusBadRequest,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testBrokenCertFile,
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusBadRequest,
 | 
			
		||||
		ExpectedSuccess:    false,
 | 
			
		||||
		ExpectedErrorCode:  1003,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafKeyFile,
 | 
			
		||||
		KeyFile:            testLeafKeyFile,
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusBadRequest,
 | 
			
		||||
		ExpectedSuccess:    false,
 | 
			
		||||
		ExpectedErrorCode:  1003,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		KeyFile:            testLeafCertFile,
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusBadRequest,
 | 
			
		||||
		ExpectedSuccess:    false,
 | 
			
		||||
		ExpectedErrorCode:  2003,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		CertFile:           testLeafCertFile,
 | 
			
		||||
		Domain:             "cloudflare-leaf.com",
 | 
			
		||||
		ExpectedHTTPStatus: http.StatusBadRequest,
 | 
			
		||||
		ExpectedSuccess:    false,
 | 
			
		||||
		ExpectedErrorCode:  1200,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBundle(t *testing.T) {
 | 
			
		||||
	for i, test := range bundleTests {
 | 
			
		||||
		resp, body := testBundleFile(t, test.Domain, test.IP, test.CertFile, test.KeyFile, test.Flavor)
 | 
			
		||||
		if resp.StatusCode != test.ExpectedHTTPStatus {
 | 
			
		||||
			t.Errorf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		message := new(api.Response)
 | 
			
		||||
		err := json.Unmarshal(body, message)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("failed to read response body: %v", err)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedSuccess != message.Success {
 | 
			
		||||
			t.Errorf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
		if test.ExpectedSuccess == true {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedErrorCode != message.Errors[0].Code {
 | 
			
		||||
			t.Errorf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client/api.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										17
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client/api.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
package client
 | 
			
		||||
 | 
			
		||||
// SignResult is the result of signing a CSR.
 | 
			
		||||
type SignResult struct {
 | 
			
		||||
	Certificate []byte `json:"certificate"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InfoReq is the request struct for an info API request.
 | 
			
		||||
type InfoReq struct {
 | 
			
		||||
	Label   string `json:"label"`
 | 
			
		||||
	Profile string `json:"profile"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InfoResp is the response for an Info API request.
 | 
			
		||||
type InfoResp struct {
 | 
			
		||||
	Certificate string `json:"certificate"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										170
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client/client.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										170
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client/client.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,170 @@
 | 
			
		|||
package client
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	stderr "errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type // A Server points to a remote CFSSL instance.
 | 
			
		||||
Server struct {
 | 
			
		||||
	Address string
 | 
			
		||||
	Port    int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewServer sets up a new server target. The address should be the
 | 
			
		||||
// DNS name (or "name:port") of the remote CFSSL instance. If no port
 | 
			
		||||
// is specified, the CFSSL default port (8888) is used.
 | 
			
		||||
func NewServer(addr string) *Server {
 | 
			
		||||
	host, port, err := net.SplitHostPort(addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		host, port, err = net.SplitHostPort(addr + ":8888")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var portno int
 | 
			
		||||
	if port == "" {
 | 
			
		||||
		portno = 8888
 | 
			
		||||
	} else {
 | 
			
		||||
		portno, err = strconv.Atoi(port)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Server{host, portno}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (srv *Server) getURL(endpoint string) string {
 | 
			
		||||
	return fmt.Sprintf("http://%s:%d/api/v1/cfssl/%s", srv.Address, srv.Port, endpoint)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// post connects to the remote server and returns a Response struct
 | 
			
		||||
func (srv *Server) post(url string, jsonData []byte) (*api.Response, error) {
 | 
			
		||||
	buf := bytes.NewBuffer(jsonData)
 | 
			
		||||
	resp, err := http.Post(url, "application/json", buf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err)
 | 
			
		||||
	}
 | 
			
		||||
	body, err := ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(errors.APIClientError, errors.IOError, err)
 | 
			
		||||
	}
 | 
			
		||||
	resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	var response api.Response
 | 
			
		||||
	err = json.Unmarshal(body, &response)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !response.Success || response.Result == nil {
 | 
			
		||||
		if len(response.Errors) > 0 {
 | 
			
		||||
			return nil, errors.Wrap(errors.APIClientError, errors.ServerRequestFailed, stderr.New(response.Errors[0].Message))
 | 
			
		||||
		}
 | 
			
		||||
		return nil, errors.New(errors.APIClientError, errors.ServerRequestFailed)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &response, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AuthSign fills out an authenticated signing request to the server,
 | 
			
		||||
// receiving a certificate or error in response.
 | 
			
		||||
// It takes the serialized JSON request to send, remote address and
 | 
			
		||||
// authentication provider.
 | 
			
		||||
func (srv *Server) AuthSign(req, id []byte, provider auth.Provider) ([]byte, error) {
 | 
			
		||||
	return srv.AuthReq(req, id, provider, "sign")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AuthInfo fills out an authenticated info request to the server,
 | 
			
		||||
// receiving a certificate or error in response.
 | 
			
		||||
// It takes the serialized JSON request to send, remote address and
 | 
			
		||||
// authentication provider.
 | 
			
		||||
func (srv *Server) AuthInfo(req, id []byte, provider auth.Provider) ([]byte, error) {
 | 
			
		||||
	return srv.AuthReq(req, id, provider, "info")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AuthReq is the common logic for AuthSign and AuthInfo -- perform the given
 | 
			
		||||
// request, and return the resultant certificate.
 | 
			
		||||
// The target is either 'sign' or 'info'.
 | 
			
		||||
func (srv *Server) AuthReq(req, ID []byte, provider auth.Provider, target string) ([]byte, error) {
 | 
			
		||||
	url := srv.getURL("auth" + target)
 | 
			
		||||
 | 
			
		||||
	token, err := provider.Token(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(errors.APIClientError, errors.AuthenticationFailure, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	aReq := &auth.AuthenticatedRequest{
 | 
			
		||||
		Timestamp:     time.Now().Unix(),
 | 
			
		||||
		RemoteAddress: ID,
 | 
			
		||||
		Token:         token,
 | 
			
		||||
		Request:       req,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jsonData, err := json.Marshal(aReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	response, err := srv.post(url, jsonData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, ok := response.Result.(map[string]interface{})
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, errors.New(errors.APIClientError, errors.JSONError)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, ok := result["certificate"].(string)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, errors.New(errors.APIClientError, errors.JSONError)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return []byte(cert), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sign sends a signature request to the remote CFSSL server,
 | 
			
		||||
// receiving a signed certificate or an error in response.
 | 
			
		||||
// It takes the serialized JSON request to send.
 | 
			
		||||
func (srv *Server) Sign(jsonData []byte) ([]byte, error) {
 | 
			
		||||
	return srv.Req(jsonData, "sign")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info sends an info request to the remote CFSSL server, receiving a
 | 
			
		||||
// certificate or an error in response.
 | 
			
		||||
// It takes the serialized JSON request to send.
 | 
			
		||||
func (srv *Server) Info(jsonData []byte) ([]byte, error) {
 | 
			
		||||
	return srv.Req(jsonData, "info")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Req performs the common logic for Sign and Info, performing the actual
 | 
			
		||||
// request and returning the resultant certificate.
 | 
			
		||||
func (srv *Server) Req(jsonData []byte, target string) ([]byte, error) {
 | 
			
		||||
	url := srv.getURL(target)
 | 
			
		||||
 | 
			
		||||
	response, err := srv.post(url, jsonData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	result := response.Result.(map[string]interface{})
 | 
			
		||||
	cert := result["certificate"].(string)
 | 
			
		||||
	if cert != "" {
 | 
			
		||||
		return []byte(cert), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New("response doesn't contain certificate."))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client/client_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										59
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client/client_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
package client
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	testProvider auth.Provider
 | 
			
		||||
	testKey      = "0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
	testAD       = []byte{1, 2, 3, 4} // IP address 1.2.3.4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNewServer(t *testing.T) {
 | 
			
		||||
	s := NewServer("1.1.1.1:::123456789")
 | 
			
		||||
 | 
			
		||||
	if s != nil {
 | 
			
		||||
		t.Fatalf("fatal error, server created with too many colons %v", s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s2 := NewServer("1.1.1.1:[]")
 | 
			
		||||
	if s != nil {
 | 
			
		||||
		t.Fatalf("%v", s2)
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, port, _ := net.SplitHostPort("")
 | 
			
		||||
	if port != "" {
 | 
			
		||||
		t.Fatalf("%v", port)
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInvalidPort(t *testing.T) {
 | 
			
		||||
	s := NewServer("1.1.1.1:99999999999999999999999999999")
 | 
			
		||||
	if s != nil {
 | 
			
		||||
		t.Fatalf("%v", s)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAuthSign(t *testing.T) {
 | 
			
		||||
	s := NewServer("1.1")
 | 
			
		||||
	testProvider, _ = auth.New(testKey, nil)
 | 
			
		||||
	testRequest := []byte(`testing 1 2 3`)
 | 
			
		||||
	as, _ := s.AuthSign(testRequest, testAD, testProvider)
 | 
			
		||||
	if as != nil {
 | 
			
		||||
		t.Fatal("fatal error with auth sign function")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSign(t *testing.T) {
 | 
			
		||||
	s := NewServer("1.1")
 | 
			
		||||
	sign, _ := s.Sign([]byte{5, 5, 5, 5})
 | 
			
		||||
	if sign != nil {
 | 
			
		||||
		t.Fatalf("%v", sign)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										300
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/generator/generator.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										300
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/generator/generator.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,300 @@
 | 
			
		|||
package generator
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/universal"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Sum contains digests for a certificate or certificate request.
 | 
			
		||||
type Sum struct {
 | 
			
		||||
	MD5  string `json:"md5"`
 | 
			
		||||
	SHA1 string `json:"sha-1"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Validator is a type of function that contains the logic for validating
 | 
			
		||||
// a certificate request.
 | 
			
		||||
type Validator func(*csr.CertificateRequest) error
 | 
			
		||||
 | 
			
		||||
// A CertRequest stores a PEM-encoded private key and corresponding
 | 
			
		||||
// CSR; this is returned from the CSR generation endpoint.
 | 
			
		||||
type CertRequest struct {
 | 
			
		||||
	Key  string         `json:"private_key"`
 | 
			
		||||
	CSR  string         `json:"certificate_request"`
 | 
			
		||||
	Sums map[string]Sum `json:"sums"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Handler accepts JSON-encoded certificate requests and
 | 
			
		||||
// returns a new private key and certificate request.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	generator *csr.Generator
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler builds a new Handler from the
 | 
			
		||||
// validation function provided.
 | 
			
		||||
func NewHandler(validator Validator) (http.Handler, error) {
 | 
			
		||||
	log.Info("setting up key / CSR generator")
 | 
			
		||||
	return &api.HTTPHandler{
 | 
			
		||||
		Handler: &Handler{
 | 
			
		||||
			generator: &csr.Generator{Validator: validator},
 | 
			
		||||
		},
 | 
			
		||||
		Method: "POST",
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func computeSum(in []byte) (sum Sum, err error) {
 | 
			
		||||
	var data []byte
 | 
			
		||||
	p, _ := pem.Decode(in)
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		err = errors.NewBadRequestString("not a CSR or certificate")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch p.Type {
 | 
			
		||||
	case "CERTIFICATE REQUEST":
 | 
			
		||||
		var req *x509.CertificateRequest
 | 
			
		||||
		req, err = x509.ParseCertificateRequest(p.Bytes)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		data = req.Raw
 | 
			
		||||
	case "CERTIFICATE":
 | 
			
		||||
		var cert *x509.Certificate
 | 
			
		||||
		cert, err = x509.ParseCertificate(p.Bytes)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		data = cert.Raw
 | 
			
		||||
	default:
 | 
			
		||||
		err = errors.NewBadRequestString("not a CSR or certificate")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	md5Sum := md5.Sum(data)
 | 
			
		||||
	sha1Sum := sha1.Sum(data)
 | 
			
		||||
	sum.MD5 = fmt.Sprintf("%X", md5Sum[:])
 | 
			
		||||
	sum.SHA1 = fmt.Sprintf("%X", sha1Sum[:])
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle responds to requests for the CA to generate a new private
 | 
			
		||||
// key and certificate request on behalf of the client. The format for
 | 
			
		||||
// these requests is documented in the API documentation.
 | 
			
		||||
func (g *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	log.Info("request for CSR")
 | 
			
		||||
	req := new(csr.CertificateRequest)
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to read request body: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = json.Unmarshal(body, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to unmarshal request: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.CA != nil {
 | 
			
		||||
		log.Warningf("request received with CA section")
 | 
			
		||||
		return errors.NewBadRequestString("ca section only permitted in initca")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	csr, key, err := g.generator.ProcessRequest(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to process CSR: %v", err)
 | 
			
		||||
		// The validator returns a *cfssl/errors.HttpError
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sum, err := computeSum(csr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Both key and csr are returned PEM-encoded.
 | 
			
		||||
	response := api.NewSuccessResponse(&CertRequest{
 | 
			
		||||
		Key:  string(key),
 | 
			
		||||
		CSR:  string(csr),
 | 
			
		||||
		Sums: map[string]Sum{"certificate_request": sum},
 | 
			
		||||
	})
 | 
			
		||||
	w.Header().Set("Content-Type", "application/json")
 | 
			
		||||
	enc := json.NewEncoder(w)
 | 
			
		||||
	err = enc.Encode(response)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A CertGeneratorHandler accepts JSON-encoded certificate requests
 | 
			
		||||
// and returns a new private key and signed certificate; it handles
 | 
			
		||||
// sending the CSR to the server.
 | 
			
		||||
type CertGeneratorHandler struct {
 | 
			
		||||
	generator *csr.Generator
 | 
			
		||||
	signer    signer.Signer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewCertGeneratorHandler builds a new handler for generating
 | 
			
		||||
// certificates directly from certificate requests; the validator covers
 | 
			
		||||
// the certificate request and the CA's key and certificate are used to
 | 
			
		||||
// sign the generated request. If remote is not an empty string, the
 | 
			
		||||
// handler will send signature requests to the CFSSL instance contained
 | 
			
		||||
// in remote.
 | 
			
		||||
func NewCertGeneratorHandler(validator Validator, caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	log.Info("setting up new generator / signer")
 | 
			
		||||
	cg := new(CertGeneratorHandler)
 | 
			
		||||
 | 
			
		||||
	if policy == nil {
 | 
			
		||||
		policy = &config.Signing{
 | 
			
		||||
			Default:  config.DefaultConfig(),
 | 
			
		||||
			Profiles: nil,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	root := universal.Root{
 | 
			
		||||
		Config: map[string]string{
 | 
			
		||||
			"ca-file":     caFile,
 | 
			
		||||
			"ca-key-file": caKeyFile,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	if cg.signer, err = universal.NewSigner(root, policy); err != nil {
 | 
			
		||||
		log.Errorf("setting up signer failed: %v", err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cg.generator = &csr.Generator{Validator: validator}
 | 
			
		||||
 | 
			
		||||
	return api.HTTPHandler{Handler: cg, Method: "POST"}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewCertGeneratorHandlerFromSigner returns a handler directly from
 | 
			
		||||
// the signer and validation function.
 | 
			
		||||
func NewCertGeneratorHandlerFromSigner(validator Validator, signer signer.Signer) http.Handler {
 | 
			
		||||
	return api.HTTPHandler{
 | 
			
		||||
		Handler: &CertGeneratorHandler{
 | 
			
		||||
			generator: &csr.Generator{Validator: validator},
 | 
			
		||||
			signer:    signer,
 | 
			
		||||
		},
 | 
			
		||||
		Method: "POST",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type genSignRequest struct {
 | 
			
		||||
	Hostname string                  `json:"hostname"`
 | 
			
		||||
	Request  *csr.CertificateRequest `json:"request"`
 | 
			
		||||
	Profile  string                  `json:"profile"`
 | 
			
		||||
	Label    string                  `json:"label"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle responds to requests for the CA to generate a new private
 | 
			
		||||
// key and certificate on behalf of the client. The format for these
 | 
			
		||||
// requests is documented in the API documentation.
 | 
			
		||||
func (cg *CertGeneratorHandler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	log.Info("request for CSR")
 | 
			
		||||
 | 
			
		||||
	req := new(genSignRequest)
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to read request body: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = json.Unmarshal(body, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to unmarshal request: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.Request == nil {
 | 
			
		||||
		log.Warning("empty request received")
 | 
			
		||||
		return errors.NewBadRequestString("missing request section")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.Request.CA != nil {
 | 
			
		||||
		log.Warningf("request received with CA section")
 | 
			
		||||
		return errors.NewBadRequestString("ca section only permitted in initca")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	csr, key, err := cg.generator.ProcessRequest(req.Request)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to process CSR: %v", err)
 | 
			
		||||
		// The validator returns a *cfssl/errors.HttpError
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var certPEM []byte
 | 
			
		||||
 | 
			
		||||
	var profile *config.SigningProfile
 | 
			
		||||
	policy := cg.signer.Policy()
 | 
			
		||||
	if policy != nil && policy.Profiles != nil && req.Profile != "" {
 | 
			
		||||
		profile = policy.Profiles[req.Profile]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if profile == nil && policy != nil {
 | 
			
		||||
		profile = policy.Default
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// This API does not override the subject because it was already added to the CSR
 | 
			
		||||
	signReq := signer.SignRequest{
 | 
			
		||||
		Hosts:   signer.SplitHosts(req.Hostname),
 | 
			
		||||
		Request: string(csr),
 | 
			
		||||
		Profile: req.Profile,
 | 
			
		||||
		Label:   req.Label,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	certBytes, err := cg.signer.Sign(signReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to sign request: %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reqSum, err := computeSum(csr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	certSum, err := computeSum(certBytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := map[string]interface{}{
 | 
			
		||||
		"private_key":         string(key),
 | 
			
		||||
		"certificate_request": string(csr),
 | 
			
		||||
		"certificate":         string(certPEM),
 | 
			
		||||
		"sums": map[string]Sum{
 | 
			
		||||
			"certificate_request": reqSum,
 | 
			
		||||
			"certificate":         certSum,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return api.SendResponse(w, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CSRValidate contains the default validation logic for certificate requests to
 | 
			
		||||
// the API server. This follows the Baseline Requirements for the Issuance and
 | 
			
		||||
// Management of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser
 | 
			
		||||
// Forum (https://cabforum.org). Specifically, section 10.2.3 ("Information
 | 
			
		||||
// Requirements"), states:
 | 
			
		||||
//
 | 
			
		||||
// "Applicant information MUST include, but not be limited to, at least one
 | 
			
		||||
// Fully-Qualified Domain Name or IP address to be included in the Certificate’s
 | 
			
		||||
// SubjectAltName extension."
 | 
			
		||||
func CSRValidate(req *csr.CertificateRequest) error {
 | 
			
		||||
	if len(req.Hosts) == 0 {
 | 
			
		||||
		log.Warning("request for CSR is missing the host parameter")
 | 
			
		||||
		return errors.NewBadRequestMissingParameter("hosts")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/generator/generator_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										70
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/generator/generator_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
package generator
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func csrData(t *testing.T) *bytes.Reader {
 | 
			
		||||
	req := &csr.CertificateRequest{
 | 
			
		||||
		Names: []csr.Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		CN:    "cloudflare.com",
 | 
			
		||||
		Hosts: []string{"cloudflare.com"},
 | 
			
		||||
		KeyRequest: &csr.KeyRequest{
 | 
			
		||||
			Algo: "ecdsa",
 | 
			
		||||
			Size: 256,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	csrBytes, err := json.Marshal(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.NewReader(csrBytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGeneratorRESTfulVerbs(t *testing.T) {
 | 
			
		||||
	handler, _ := NewHandler(CSRValidate)
 | 
			
		||||
	ts := httptest.NewServer(handler)
 | 
			
		||||
	data := csrData(t)
 | 
			
		||||
	// POST should work.
 | 
			
		||||
	req, _ := http.NewRequest("POST", ts.URL, data)
 | 
			
		||||
	resp, _ := http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Test GET, PUT, DELETE and whatever, expect 400 errors.
 | 
			
		||||
	req, _ = http.NewRequest("GET", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
	req, _ = http.NewRequest("PUT", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
	req, _ = http.NewRequest("DELETE", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
	req, _ = http.NewRequest("WHATEVER", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/info/info.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										62
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/info/info.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
package info
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/cloudflare/cfssl/bundler"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Handler is a type that contains the root certificates for the CA,
 | 
			
		||||
// and serves information on them for clients that need the certificates.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	sign signer.Signer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler creates a new handler to serve information on the CA's
 | 
			
		||||
// certificates, taking a signer to use.
 | 
			
		||||
func NewHandler(s signer.Signer) (http.Handler, error) {
 | 
			
		||||
	return &api.HTTPHandler{
 | 
			
		||||
		Handler: &Handler{
 | 
			
		||||
			sign: s,
 | 
			
		||||
		},
 | 
			
		||||
		Method: "POST",
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle listens for incoming requests for CA information, and returns
 | 
			
		||||
// a list containing information on each root certificate.
 | 
			
		||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
 | 
			
		||||
	req := new(client.InfoReq)
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to read request body: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
	err = json.Unmarshal(body, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to unmarshal request: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, err := h.sign.Certificate(req.Label, req.Profile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	resp := client.InfoResp{
 | 
			
		||||
		Certificate: bundler.PemBlockToString(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	response := api.NewSuccessResponse(resp)
 | 
			
		||||
	w.Header().Set("Content-Type", "application/json")
 | 
			
		||||
	enc := json.NewEncoder(w)
 | 
			
		||||
	return enc.Encode(response)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										127
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/info/info_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										127
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/info/info_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,127 @@
 | 
			
		|||
package info
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testCaFile    = "../testdata/ca.pem"
 | 
			
		||||
	testCaKeyFile = "../testdata/ca_key.pem"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newTestHandler(t *testing.T) (h http.Handler) {
 | 
			
		||||
	signer, err := local.NewSignerFromFile(testCaFile, testCaKeyFile, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h, err = NewHandler(signer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewHandler(t *testing.T) {
 | 
			
		||||
	newTestHandler(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newInfoServer(t *testing.T) *httptest.Server {
 | 
			
		||||
	ts := httptest.NewServer(newTestHandler(t))
 | 
			
		||||
	return ts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testInfoFile(t *testing.T, req map[string]interface{}) (resp *http.Response, body []byte) {
 | 
			
		||||
	ts := newInfoServer(t)
 | 
			
		||||
	defer ts.Close()
 | 
			
		||||
 | 
			
		||||
	blob, err := json.Marshal(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	body, err = ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type infoTest struct {
 | 
			
		||||
	RequestObject      map[string]interface{}
 | 
			
		||||
	ExpectedHTTPStatus int
 | 
			
		||||
	ExpectedSuccess    bool
 | 
			
		||||
	ExpectedErrorCode  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var infoTests = []infoTest{
 | 
			
		||||
	{
 | 
			
		||||
		map[string]interface{}{
 | 
			
		||||
			"label":   "",
 | 
			
		||||
			"profile": "",
 | 
			
		||||
		},
 | 
			
		||||
		http.StatusOK,
 | 
			
		||||
		true,
 | 
			
		||||
		0,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		map[string]interface{}{
 | 
			
		||||
			"label":   "badlabel",
 | 
			
		||||
			"profile": "",
 | 
			
		||||
		},
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
		false,
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		map[string]interface{}{
 | 
			
		||||
			"label": 123,
 | 
			
		||||
		},
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
		false,
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInfo(t *testing.T) {
 | 
			
		||||
	for i, test := range infoTests {
 | 
			
		||||
		resp, body := testInfoFile(t, test.RequestObject)
 | 
			
		||||
		if resp.StatusCode != test.ExpectedHTTPStatus {
 | 
			
		||||
			t.Fatalf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		message := new(api.Response)
 | 
			
		||||
		err := json.Unmarshal(body, message)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatalf("failed to read response body: %v", err)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedSuccess != message.Success {
 | 
			
		||||
			t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
		if test.ExpectedSuccess == true {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedErrorCode != message.Errors[0].Code {
 | 
			
		||||
			t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/initca/initca.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										58
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/initca/initca.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
package initca
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/cloudflare/cfssl/initca"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A NewCA contains a private key and certificate suitable for serving
 | 
			
		||||
// as the root key for a new certificate authority.
 | 
			
		||||
type NewCA struct {
 | 
			
		||||
	Key  string `json:"private_key"`
 | 
			
		||||
	Cert string `json:"certificate"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// initialCAHandler is an HTTP handler that accepts a JSON blob in the
 | 
			
		||||
// same format as the CSR endpoint; this blob should contain the
 | 
			
		||||
// identity information for the CA's root key. This endpoint is not
 | 
			
		||||
// suitable for creating intermediate certificates.
 | 
			
		||||
func initialCAHandler(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	log.Info("setting up initial CA handler")
 | 
			
		||||
	req := new(csr.CertificateRequest)
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to read request body: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = json.Unmarshal(body, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to unmarshal request: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key, cert, err := initca.New(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to initialise new CA: %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	response := api.NewSuccessResponse(&NewCA{string(key), string(cert)})
 | 
			
		||||
 | 
			
		||||
	enc := json.NewEncoder(w)
 | 
			
		||||
	err = enc.Encode(response)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler returns a new http.Handler that handles request to
 | 
			
		||||
// initialize a CA.
 | 
			
		||||
func NewHandler() http.Handler {
 | 
			
		||||
	return api.HTTPHandler{Handler: api.HandlerFunc(initialCAHandler), Method: "POST"}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										69
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/initca/initca_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										69
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/initca/initca_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
package initca
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func csrData(t *testing.T) *bytes.Reader {
 | 
			
		||||
	req := &csr.CertificateRequest{
 | 
			
		||||
		Names: []csr.Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		CN:    "cloudflare.com",
 | 
			
		||||
		Hosts: []string{"cloudflare.com"},
 | 
			
		||||
		KeyRequest: &csr.KeyRequest{
 | 
			
		||||
			Algo: "ecdsa",
 | 
			
		||||
			Size: 256,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	csrBytes, err := json.Marshal(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.NewReader(csrBytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInitCARESTfulVerbs(t *testing.T) {
 | 
			
		||||
	ts := httptest.NewServer(NewHandler())
 | 
			
		||||
	data := csrData(t)
 | 
			
		||||
	// POST should work.
 | 
			
		||||
	req, _ := http.NewRequest("POST", ts.URL, data)
 | 
			
		||||
	resp, _ := http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Test GET, PUT, DELETE and whatever, expect 400 errors.
 | 
			
		||||
	req, _ = http.NewRequest("GET", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
	req, _ = http.NewRequest("PUT", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
	req, _ = http.NewRequest("DELETE", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
	req, _ = http.NewRequest("WHATEVER", ts.URL, data)
 | 
			
		||||
	resp, _ = http.DefaultClient.Do(req)
 | 
			
		||||
	if resp.StatusCode != http.StatusMethodNotAllowed {
 | 
			
		||||
		t.Fatal(resp.Status)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										314
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/sign/sign.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										314
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/sign/sign.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,314 @@
 | 
			
		|||
package sign
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/universal"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Handler accepts requests with a hostname and certficate
 | 
			
		||||
// parameter (which should be PEM-encoded) and returns a new signed
 | 
			
		||||
// certificate. It includes upstream servers indexed by their
 | 
			
		||||
// profile name.
 | 
			
		||||
type Handler struct {
 | 
			
		||||
	signer signer.Signer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandler generates a new Handler using the certificate
 | 
			
		||||
// authority private key and certficate to sign certificates. If remote
 | 
			
		||||
// is not an empty string, the handler will send signature requests to
 | 
			
		||||
// the CFSSL instance contained in remote by default.
 | 
			
		||||
func NewHandler(caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) {
 | 
			
		||||
	root := universal.Root{
 | 
			
		||||
		Config: map[string]string{
 | 
			
		||||
			"cert-file": caFile,
 | 
			
		||||
			"key-file":  caKeyFile,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	s, err := universal.NewSigner(root, policy)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("setting up signer failed: %v", err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewHandlerFromSigner(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHandlerFromSigner generates a new Handler directly from
 | 
			
		||||
// an existing signer.
 | 
			
		||||
func NewHandlerFromSigner(signer signer.Signer) (h *api.HTTPHandler, err error) {
 | 
			
		||||
	policy := signer.Policy()
 | 
			
		||||
	if policy == nil {
 | 
			
		||||
		err = errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Sign will only respond for profiles that have no auth provider.
 | 
			
		||||
	// So if all of the profiles require authentication, we return an error.
 | 
			
		||||
	haveUnauth := (policy.Default.Provider == nil)
 | 
			
		||||
	for _, profile := range policy.Profiles {
 | 
			
		||||
		if haveUnauth {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		haveUnauth = (profile.Provider == nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !haveUnauth {
 | 
			
		||||
		err = errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &api.HTTPHandler{
 | 
			
		||||
		Handler: &Handler{
 | 
			
		||||
			signer: signer,
 | 
			
		||||
		},
 | 
			
		||||
		Method: "POST",
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This type is meant to be unmarshalled from JSON so that there can be a
 | 
			
		||||
// hostname field in the API
 | 
			
		||||
// TODO: Change the API such that the normal struct can be used.
 | 
			
		||||
type jsonSignRequest struct {
 | 
			
		||||
	Hostname string          `json:"hostname"`
 | 
			
		||||
	Hosts    []string        `json:"hosts"`
 | 
			
		||||
	Request  string          `json:"certificate_request"`
 | 
			
		||||
	Subject  *signer.Subject `json:"subject,omitempty"`
 | 
			
		||||
	Profile  string          `json:"profile"`
 | 
			
		||||
	Label    string          `json:"label"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func jsonReqToTrue(js jsonSignRequest) signer.SignRequest {
 | 
			
		||||
	sub := new(signer.Subject)
 | 
			
		||||
	if js.Subject == nil {
 | 
			
		||||
		sub = nil
 | 
			
		||||
	} else {
 | 
			
		||||
		// make a copy
 | 
			
		||||
		*sub = *js.Subject
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if js.Hostname != "" {
 | 
			
		||||
		return signer.SignRequest{
 | 
			
		||||
			Hosts:   signer.SplitHosts(js.Hostname),
 | 
			
		||||
			Subject: sub,
 | 
			
		||||
			Request: js.Request,
 | 
			
		||||
			Profile: js.Profile,
 | 
			
		||||
			Label:   js.Label,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return signer.SignRequest{
 | 
			
		||||
		Hosts:   js.Hosts,
 | 
			
		||||
		Subject: sub,
 | 
			
		||||
		Request: js.Request,
 | 
			
		||||
		Profile: js.Profile,
 | 
			
		||||
		Label:   js.Label,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle responds to requests for the CA to sign the certificate request
 | 
			
		||||
// present in the "certificate_request" parameter for the host named
 | 
			
		||||
// in the "hostname" parameter. The certificate should be PEM-encoded. If
 | 
			
		||||
// provided, subject information from the "subject" parameter will be used
 | 
			
		||||
// in place of the subject information from the CSR.
 | 
			
		||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	log.Info("signature request received")
 | 
			
		||||
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	r.Body.Close()
 | 
			
		||||
 | 
			
		||||
	var req jsonSignRequest
 | 
			
		||||
 | 
			
		||||
	err = json.Unmarshal(body, &req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.NewBadRequestString("Unable to parse sign request")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	signReq := jsonReqToTrue(req)
 | 
			
		||||
	if len(signReq.Hosts) == 0 {
 | 
			
		||||
		return errors.NewBadRequestString("missing parameter 'hostname' or 'hosts'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.Request == "" {
 | 
			
		||||
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var cert []byte
 | 
			
		||||
	var profile *config.SigningProfile
 | 
			
		||||
 | 
			
		||||
	policy := h.signer.Policy()
 | 
			
		||||
	if policy != nil && policy.Profiles != nil && req.Profile != "" {
 | 
			
		||||
		profile = policy.Profiles[req.Profile]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if profile == nil && policy != nil {
 | 
			
		||||
		profile = policy.Default
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if profile.Provider != nil {
 | 
			
		||||
		log.Error("profile requires authentication")
 | 
			
		||||
		return errors.NewBadRequestString("authentication required")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, err = h.signer.Sign(signReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to sign request: %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := map[string]string{"certificate": string(cert)}
 | 
			
		||||
	log.Info("wrote response")
 | 
			
		||||
	return api.SendResponse(w, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An AuthHandler verifies and signs incoming signature requests.
 | 
			
		||||
type AuthHandler struct {
 | 
			
		||||
	signer signer.Signer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewAuthHandler generates a new AuthHandler using the certificate
 | 
			
		||||
// authority private key and certficate to sign certificates. If remote
 | 
			
		||||
// is not an empty string, the handler will send signature requests to
 | 
			
		||||
// the CFSSL instance contained in remote by default.
 | 
			
		||||
func NewAuthHandler(caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) {
 | 
			
		||||
	root := universal.Root{
 | 
			
		||||
		Config: map[string]string{
 | 
			
		||||
			"cert-file": caFile,
 | 
			
		||||
			"key-file":  caKeyFile,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	s, err := universal.NewSigner(root, policy)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("setting up signer failed: %v", err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewAuthHandlerFromSigner(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewAuthHandlerFromSigner creates a new AuthHandler from the signer
 | 
			
		||||
// that is passed in.
 | 
			
		||||
func NewAuthHandlerFromSigner(signer signer.Signer) (http.Handler, error) {
 | 
			
		||||
	policy := signer.Policy()
 | 
			
		||||
	if policy == nil {
 | 
			
		||||
		return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if policy.Default == nil && policy.Profiles == nil {
 | 
			
		||||
		return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// AuthSign will not respond for profiles that have no auth provider.
 | 
			
		||||
	// So if there are no profiles with auth providers in this policy,
 | 
			
		||||
	// we return an error.
 | 
			
		||||
	haveAuth := (policy.Default.Provider != nil)
 | 
			
		||||
	for _, profile := range policy.Profiles {
 | 
			
		||||
		if haveAuth {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		haveAuth = (profile.Provider != nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !haveAuth {
 | 
			
		||||
		return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &api.HTTPHandler{
 | 
			
		||||
		Handler: &AuthHandler{
 | 
			
		||||
			signer: signer,
 | 
			
		||||
		},
 | 
			
		||||
		Method: "POST",
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle receives the incoming request, validates it, and processes it.
 | 
			
		||||
func (h *AuthHandler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	log.Info("signature request received")
 | 
			
		||||
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("failed to read response body: %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	r.Body.Close()
 | 
			
		||||
 | 
			
		||||
	var aReq auth.AuthenticatedRequest
 | 
			
		||||
	err = json.Unmarshal(body, &aReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("failed to unmarshal authenticated request: %v", err)
 | 
			
		||||
		return errors.NewBadRequest(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var req jsonSignRequest
 | 
			
		||||
	err = json.Unmarshal(aReq.Request, &req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("failed to unmarshal request from authenticated request: %v", err)
 | 
			
		||||
		return errors.NewBadRequestString("Unable to parse authenticated sign request")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	signReq := jsonReqToTrue(req)
 | 
			
		||||
	if len(signReq.Hosts) == 0 {
 | 
			
		||||
		return errors.NewBadRequestString("missing parameter 'hostname' or 'hosts'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.Request == "" {
 | 
			
		||||
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Sanity checks to ensure that we have a valid policy. This
 | 
			
		||||
	// should have been checked in NewAuthHandler.
 | 
			
		||||
	policy := h.signer.Policy()
 | 
			
		||||
	if policy == nil {
 | 
			
		||||
		log.Critical("signer was initialised without a signing policy")
 | 
			
		||||
		return errors.NewBadRequestString("invalid policy")
 | 
			
		||||
	}
 | 
			
		||||
	profile := policy.Default
 | 
			
		||||
 | 
			
		||||
	if policy.Profiles != nil {
 | 
			
		||||
		profile = policy.Profiles[req.Profile]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if profile == nil {
 | 
			
		||||
		log.Critical("signer was initialised without any valid profiles")
 | 
			
		||||
		return errors.NewBadRequestString("invalid profile")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if profile.Provider == nil {
 | 
			
		||||
		log.Error("profile has no authentication provider")
 | 
			
		||||
		return errors.NewBadRequestString("no authentication provider")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !profile.Provider.Verify(&aReq) {
 | 
			
		||||
		log.Warning("received authenticated request with invalid token")
 | 
			
		||||
		return errors.NewBadRequestString("invalid token")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.Hostname == "" && len(req.Hosts) == 0 {
 | 
			
		||||
		return errors.NewBadRequestString("missing hostnames")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.Request == "" {
 | 
			
		||||
		return errors.NewBadRequestString("missing certificate_request parameter")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, err := h.signer.Sign(jsonReqToTrue(req))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("signature failed: %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := map[string]string{"certificate": string(cert)}
 | 
			
		||||
	log.Info("wrote response")
 | 
			
		||||
	return api.SendResponse(w, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										400
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/sign/sign_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										400
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/sign/sign_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,400 @@
 | 
			
		|||
package sign
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testCaFile         = "../testdata/ca.pem"
 | 
			
		||||
	testCaKeyFile      = "../testdata/ca_key.pem"
 | 
			
		||||
	testCSRFile        = "../testdata/csr.pem"
 | 
			
		||||
	testBrokenCertFile = "../testdata/broken.pem"
 | 
			
		||||
	testBrokenCSRFile  = "../testdata/broken_csr.pem"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var validLocalConfig = `
 | 
			
		||||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "1m"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
var validAuthLocalConfig = `
 | 
			
		||||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "1m",
 | 
			
		||||
			"auth_key": "sample"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"sample": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
func newTestHandler(t *testing.T) (h http.Handler) {
 | 
			
		||||
	h, err := NewHandler(testCaFile, testCaKeyFile, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewHandler(t *testing.T) {
 | 
			
		||||
	newTestHandler(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewHandlerWithProfile(t *testing.T) {
 | 
			
		||||
	conf, err := config.LoadConfig([]byte(validLocalConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = NewHandler(testCaFile, testCaKeyFile, conf.Signing)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewHandlerWithAuthProfile(t *testing.T) {
 | 
			
		||||
	conf, err := config.LoadConfig([]byte(validAuthLocalConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = NewHandler(testCaFile, testCaKeyFile, conf.Signing)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("All profiles have auth keys. Should have failed to create non-auth sign handler.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewHandlerError(t *testing.T) {
 | 
			
		||||
	// using testBrokenCSRFile as badly formed key
 | 
			
		||||
	_, err := NewHandler(testCaFile, testBrokenCSRFile, nil)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Expect error when create a signer with broken file.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newSignServer(t *testing.T) *httptest.Server {
 | 
			
		||||
	ts := httptest.NewServer(newTestHandler(t))
 | 
			
		||||
	return ts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testSignFileOldInterface(t *testing.T, hostname, csrFile string) (resp *http.Response, body []byte) {
 | 
			
		||||
	ts := newSignServer(t)
 | 
			
		||||
	defer ts.Close()
 | 
			
		||||
	var csrPEM []byte
 | 
			
		||||
	if csrFile != "" {
 | 
			
		||||
		var err error
 | 
			
		||||
		csrPEM, err = ioutil.ReadFile(csrFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	obj := map[string]string{}
 | 
			
		||||
	if len(hostname) > 0 {
 | 
			
		||||
		obj["hostname"] = hostname
 | 
			
		||||
	}
 | 
			
		||||
	if len(csrPEM) > 0 {
 | 
			
		||||
		obj["certificate_request"] = string(csrPEM)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blob, err := json.Marshal(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	body, err = ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testSignFile(t *testing.T, hostname, csrFile string) (resp *http.Response, body []byte) {
 | 
			
		||||
	ts := newSignServer(t)
 | 
			
		||||
	defer ts.Close()
 | 
			
		||||
	var csrPEM []byte
 | 
			
		||||
	if csrFile != "" {
 | 
			
		||||
		var err error
 | 
			
		||||
		csrPEM, err = ioutil.ReadFile(csrFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	obj := map[string]interface{}{}
 | 
			
		||||
	if len(hostname) > 0 {
 | 
			
		||||
		obj["hosts"] = []string{hostname}
 | 
			
		||||
	}
 | 
			
		||||
	if len(csrPEM) > 0 {
 | 
			
		||||
		obj["certificate_request"] = string(csrPEM)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blob, err := json.Marshal(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	body, err = ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testHostName   = "localhost"
 | 
			
		||||
	testDomainName = "cloudflare.com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type signTest struct {
 | 
			
		||||
	Hostname           string
 | 
			
		||||
	CSRFile            string
 | 
			
		||||
	ExpectedHTTPStatus int
 | 
			
		||||
	ExpectedSuccess    bool
 | 
			
		||||
	ExpectedErrorCode  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var signTests = []signTest{
 | 
			
		||||
	{
 | 
			
		||||
		testHostName,
 | 
			
		||||
		testCSRFile,
 | 
			
		||||
		http.StatusOK,
 | 
			
		||||
		true,
 | 
			
		||||
		0,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		testDomainName,
 | 
			
		||||
		testCSRFile,
 | 
			
		||||
		http.StatusOK,
 | 
			
		||||
		true,
 | 
			
		||||
		0,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"",
 | 
			
		||||
		testCSRFile,
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
		false,
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		testDomainName,
 | 
			
		||||
		"",
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
		false,
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		testDomainName,
 | 
			
		||||
		testBrokenCSRFile,
 | 
			
		||||
		http.StatusBadRequest,
 | 
			
		||||
		false,
 | 
			
		||||
		1002,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSign(t *testing.T) {
 | 
			
		||||
	for i, test := range signTests {
 | 
			
		||||
		resp, body := testSignFile(t, test.Hostname, test.CSRFile)
 | 
			
		||||
		if resp.StatusCode != test.ExpectedHTTPStatus {
 | 
			
		||||
			t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		message := new(api.Response)
 | 
			
		||||
		err := json.Unmarshal(body, message)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Logf("failed to read response body: %v", err)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedSuccess != message.Success {
 | 
			
		||||
			t.Logf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
		if test.ExpectedSuccess == true {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedErrorCode != message.Errors[0].Code {
 | 
			
		||||
			t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Test for backward compatibility
 | 
			
		||||
	// TODO remove after API transition is complete.
 | 
			
		||||
	for i, test := range signTests {
 | 
			
		||||
		resp, body := testSignFileOldInterface(t, test.Hostname, test.CSRFile)
 | 
			
		||||
		if resp.StatusCode != test.ExpectedHTTPStatus {
 | 
			
		||||
			t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		message := new(api.Response)
 | 
			
		||||
		err := json.Unmarshal(body, message)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Logf("failed to read response body: %v", err)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedSuccess != message.Success {
 | 
			
		||||
			t.Logf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
		if test.ExpectedSuccess == true {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedErrorCode != message.Errors[0].Code {
 | 
			
		||||
			t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newTestAuthHandler(t *testing.T) http.Handler {
 | 
			
		||||
	conf, err := config.LoadConfig([]byte(validAuthLocalConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h, err := NewAuthHandler(testCaFile, testCaKeyFile, conf.Signing)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewAuthHandler(t *testing.T) {
 | 
			
		||||
	newTestAuthHandler(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewAuthHandlerWithNoAuthConfig(t *testing.T) {
 | 
			
		||||
	conf, err := config.LoadConfig([]byte(validLocalConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = NewAuthHandler(testCaFile, testCaKeyFile, conf.Signing)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Config doesn't have auth keys. Should have failed.")
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testAuthSignFile(t *testing.T, hostname, csrFile string, profile *config.SigningProfile) (resp *http.Response, body []byte) {
 | 
			
		||||
	ts := newAuthSignServer(t)
 | 
			
		||||
	defer ts.Close()
 | 
			
		||||
 | 
			
		||||
	var csrPEM []byte
 | 
			
		||||
	if csrFile != "" {
 | 
			
		||||
		var err error
 | 
			
		||||
		csrPEM, err = ioutil.ReadFile(csrFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	obj := map[string]string{}
 | 
			
		||||
	if len(hostname) > 0 {
 | 
			
		||||
		obj["hostname"] = hostname
 | 
			
		||||
	}
 | 
			
		||||
	if len(csrPEM) > 0 {
 | 
			
		||||
		obj["certificate_request"] = string(csrPEM)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reqBlob, err := json.Marshal(obj)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var aReq auth.AuthenticatedRequest
 | 
			
		||||
	aReq.Request = reqBlob
 | 
			
		||||
	aReq.Token, err = profile.Provider.Token(aReq.Request)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blob, err := json.Marshal(aReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	body, err = ioutil.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newAuthSignServer(t *testing.T) *httptest.Server {
 | 
			
		||||
	ts := httptest.NewServer(newTestAuthHandler(t))
 | 
			
		||||
	return ts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAuthSign(t *testing.T) {
 | 
			
		||||
	conf, err := config.LoadConfig([]byte(validAuthLocalConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	for i, test := range signTests {
 | 
			
		||||
		resp, body := testAuthSignFile(t, test.Hostname, test.CSRFile, conf.Signing.Default)
 | 
			
		||||
		if resp.StatusCode != test.ExpectedHTTPStatus {
 | 
			
		||||
			t.Logf("Test %d: expected: %d, have %d", i, test.ExpectedHTTPStatus, resp.StatusCode)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, string(body))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		message := new(api.Response)
 | 
			
		||||
		err := json.Unmarshal(body, message)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Logf("failed to read response body: %v", err)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedSuccess != message.Success {
 | 
			
		||||
			t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedSuccess, message.Success)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
		if test.ExpectedSuccess == true {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if test.ExpectedErrorCode != message.Errors[0].Code {
 | 
			
		||||
			t.Fatalf("Test %d: expected: %v, have %v", i, test.ExpectedErrorCode, message.Errors[0].Code)
 | 
			
		||||
			t.Fatal(resp.Status, test.ExpectedHTTPStatus, message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/broken.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/broken.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIICATCCAWoCCQDidF+uNJR6czANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
 | 
			
		||||
cyBQdHkgTHRkMB4XDTEyMDUwMTIyNTUxN1oXDTEzMDUwMTIyNTUxN1owRTELMAkG
 | 
			
		||||
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
 | 
			
		||||
nodhz31kLEJoeLSkRmrv8l7exkGtO0REtIbirj9BBy64ZXVBE7khKGO2cnM8U7yj
 | 
			
		||||
w7Ntfh+IvCjZVA3d2XqHS3Pjrt4HmU/cGCONE8+NEXoqdzLUDPOix1qDDRBvXs81
 | 
			
		||||
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtpjl
 | 
			
		||||
KAV2qh6CYHZbdqixhDerjvJcD4Nsd7kExEZfHuECAwEAATANBgkqhkiG9w0BAQUF
 | 
			
		||||
AAOBgQCyOqs7+qpMrYCgL6OamDeCVojLoEp036PsnaYWf2NPmsVXdpYW40Foyyjp
 | 
			
		||||
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
 | 
			
		||||
iv5otkxO5rxtGPv7o2J1eMBpCuSkydvoz3Ey/QwGqbBwEXQ4xYCgra336gqW2KQt
 | 
			
		||||
+LnDCkE8f5oBhCIisExc2i8PDvsRsY70g/2gs983ImJjVR8sDw==
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										30
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/broken_csr.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										30
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/broken_csr.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIFGzCCAwUCAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl
 | 
			
		||||
LWludGVyLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOUKdX6+
 | 
			
		||||
PSxU/LxKocsCUj7HCc+FaDOPZV68Po3PVm7UF5DmbnLgJYJ/4aZEZM/v5r8LnXQX
 | 
			
		||||
DqumYicHQ2DHHBDasLTx8m0KeKOUYf9WMQ8gdjmVFoCiZwzxGDHok66/0Glkkqmv
 | 
			
		||||
2nJQxXncl5ZFta4sfmcQx3KT02l61LaBbG3j8PbRCWEr+0eRE6twuYRR13AgZ3AT
 | 
			
		||||
wnMjzxzvsW67qmAy0cq+XgYYfTK9vhPs+8J0fxXa0Iftu3yuhd30xLIVXLu45GR+
 | 
			
		||||
i6KnsSxVERSaVxjkS+lHXjUpdtmqI5CK6wn67vqYRRA2TzAJHX8Jb+KL2/UEo5WN
 | 
			
		||||
fAJ8S0heODQA8nHVU1JIfpegOlQRMv55DgnQUv1c1uwO5hqvv7MPQ3X/m9Kjccs1
 | 
			
		||||
FBH1/SVuzKyxYEQ34LErX3HI+6avbVnRtTR/UHkfnZVIXSrcjUm73BGj33hrtiKl
 | 
			
		||||
0ZyZnaUKGZPuvebOUFNiXemhTbqrfi/zAb1Tsm/h+xkn5EZ5sMj5NHdAbpih3TqX
 | 
			
		||||
2gRhnFZcFjtJM6zzC5O7eG5Kdqf8iladXTXtWxzrUPkb5CupzFl1dyS3dqdkoIXv
 | 
			
		||||
kmlScnu+6jBOaYeVvwogxr2Y69y4Zfg/qbPyBOLZquX9ovbuSP1DQmC//LV5t7YH
 | 
			
		||||
HY/1MXr5U0MMvcn+9JWUV6ou3at4AgEqfK0vAgMBAAGgSzBJBgkqhkiG9w0BCQ4x
 | 
			
		||||
PDA6MDgGA1UdEQQxMC+CFGNsb3VkZmxhcmUtaW50ZXIuY29tghd3d3djbG91ZGZs
 | 
			
		||||
YXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQ0DggIBAHtSt/v+IHQmSK5UiQWwjRWA
 | 
			
		||||
ZezIWVlJuselW8DEPNHzDtnraVhjPSFP995Cqh9fc89kx2Bt9hDhjNteTB+pJW6B
 | 
			
		||||
aCRRZygJ6/m3Ii1XqTFgfEJBWwuIX1Req0PCW/ayegdLzzYbSZ31wRICCveBQyGw
 | 
			
		||||
vRtzIBUeMvz9MgLJ8zx7eN7fDhrvy+Y1SkC4g0sAQTYYfM9P/He4k5hx79hmd2YC
 | 
			
		||||
mUDAlNZV0g0dY0qR4cITmhniIFW5iZBplY7DmqooUXrj5yEga2QMj/RA16lPzHbz
 | 
			
		||||
7ceUlcH2L6/V6zMR/rfCiGRoWInxWSuuJhLIVLmoEo0590w6KVEZifHxsRpl4l09
 | 
			
		||||
imvzwTSQGIrY8jF9AxOD0rRA9wXCT9h8XtBWyJZ1/DmzJG8+7oZ/HdE9XhzwNujD
 | 
			
		||||
Q6lBOj+dznju7k/snYCZVq501JLPeql8vQrq0O/xSqSK4yN1IG4NisZeDK2BZEOy
 | 
			
		||||
QhnKXodIKf+zXnFw86lZ/ZwHQFr6jOSxmbrZ2OiY34m7Yd9oeIaMPviysRih2x4Q
 | 
			
		||||
O6DFz72f97+xFZuXIbmn8DPQV8U9bk/gbrfUCPnx/icS8UoPsBKc9Gio0FZO4+8A
 | 
			
		||||
4/ac3oeN0zy/WjsBP+J50CRUXMrRI9KO+/bI4pcT14B31YbuSo6ygIkIkj7YDh36
 | 
			
		||||
+4ZG6HnUPQI8HteF9hzp=BROKEN==
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										17
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/ca-bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										17
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/ca-bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIICyDCCAjGgAwIBAgIJAPCgd7rafQZGMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNV
 | 
			
		||||
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
 | 
			
		||||
c2NvMRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEW
 | 
			
		||||
MBQGA1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDA0MTExNjQyMjBaFw0yNDA0MDgx
 | 
			
		||||
NjQyMjBaMH0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYD
 | 
			
		||||
VQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQL
 | 
			
		||||
DAtERVZfVEVTVElORzEWMBQGA1UEAwwNQ0ZTU0xfVEVTVF9DQTCBnzANBgkqhkiG
 | 
			
		||||
9w0BAQEFAAOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1CMS59jJOL
 | 
			
		||||
omfDnKUWOGKi/k7URBg1HNL3vm7/ESDazZWFy9l/nibWxNkSUPkQIrvrGsNivkRU
 | 
			
		||||
zXkwgNX8IN8LOYAQ3BWxAqitXTpLjf4FeCTB6G59v9eYlAX3kicXRdY+cqhEvLFb
 | 
			
		||||
u3MCAwEAAaNQME4wHQYDVR0OBBYEFLhe765nULfW8wflar5Vs2c6DZI+MB8GA1Ud
 | 
			
		||||
IwQYMBaAFLhe765nULfW8wflar5Vs2c6DZI+MAwGA1UdEwQFMAMBAf8wDQYJKoZI
 | 
			
		||||
hvcNAQEFBQADgYEABYqqOUq3ZrtMYaTAoeA7Cr/OBMjBV+/TiOe8fRNoPZ7+aKSg
 | 
			
		||||
E1baohCGqougm+/XOtBXeLv5tVQihz/2iKdwHmX4HjkxzevAXyazjxeW4IDA21Jl
 | 
			
		||||
fKd7xUJHM0Du/opoDkXWr/vRVztOB33ndlAK7ruSLfTR3E9HoUe3aRH7ceQ=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw
 | 
			
		||||
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
 | 
			
		||||
YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT
 | 
			
		||||
VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx
 | 
			
		||||
MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV
 | 
			
		||||
BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT
 | 
			
		||||
CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG
 | 
			
		||||
SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
 | 
			
		||||
MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4
 | 
			
		||||
BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d
 | 
			
		||||
hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt
 | 
			
		||||
HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw
 | 
			
		||||
aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN
 | 
			
		||||
8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3
 | 
			
		||||
0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p
 | 
			
		||||
/YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
 | 
			
		||||
aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx
 | 
			
		||||
GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz
 | 
			
		||||
dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq
 | 
			
		||||
hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3
 | 
			
		||||
F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc
 | 
			
		||||
depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet
 | 
			
		||||
Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv
 | 
			
		||||
qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd
 | 
			
		||||
H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ==
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
-----BEGIN PRIVATE KEY-----
 | 
			
		||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j
 | 
			
		||||
QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T
 | 
			
		||||
Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE
 | 
			
		||||
x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi
 | 
			
		||||
EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD
 | 
			
		||||
61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io
 | 
			
		||||
1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD
 | 
			
		||||
N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8
 | 
			
		||||
c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc
 | 
			
		||||
YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h
 | 
			
		||||
HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI
 | 
			
		||||
AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+
 | 
			
		||||
cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1
 | 
			
		||||
/2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P
 | 
			
		||||
kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt
 | 
			
		||||
hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz
 | 
			
		||||
cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/
 | 
			
		||||
uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E
 | 
			
		||||
wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p
 | 
			
		||||
PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq
 | 
			
		||||
4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk
 | 
			
		||||
s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27
 | 
			
		||||
ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43
 | 
			
		||||
rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi
 | 
			
		||||
0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV
 | 
			
		||||
xQB518/lp2eIeMpglWByDwJX
 | 
			
		||||
-----END PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/cert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/cert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
 | 
			
		||||
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy
 | 
			
		||||
MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd
 | 
			
		||||
MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C
 | 
			
		||||
MS59jJOLomfDnKUWOGKi/k7URBg1HNL3vm7/ESDazZWFy9l/nibWxNkSUPkQIrvr
 | 
			
		||||
GsNivkRUzXkwgNX8IN8LOYAQ3BWxAqitXTpLjf4FeCTB6G59v9eYlAX3kicXRdY+
 | 
			
		||||
cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME
 | 
			
		||||
MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m
 | 
			
		||||
dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi
 | 
			
		||||
uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O
 | 
			
		||||
aq+K7aVrgHkPnWeRiG6tl+ZA
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										12
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/csr.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										12
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/csr.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIB0jCCAVcCAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl
 | 
			
		||||
LWludGVyLmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABCFZIzSRsH9xdF1iR+8k
 | 
			
		||||
ElbcbqAYnYuSTbEOxYcREHGRJd2/v9YhetEwWNmIuisCbgOpyBO9zyFxsnzYU4cO
 | 
			
		||||
A/AomW2nJEP7n4M9g8r8clhQz8y6+013jP9MEqf4pqMVnqBLMEkGCSqGSIb3DQEJ
 | 
			
		||||
DjE8MDowOAYDVR0RBDEwL4IUY2xvdWRmbGFyZS1pbnRlci5jb22CF3d3d2Nsb3Vk
 | 
			
		||||
ZmxhcmUtaW50ZXIuY29tMAoGCCqGSM49BAMDA2kAMGYCMQD6kSGGc3/DeFAWrPUX
 | 
			
		||||
qSlnTTm57DpzUoHQE306DfbFB6DFfoORNM5Z98chnZ+Ell4CMQCzYhOvIh3+GPGF
 | 
			
		||||
MuYYIAfQV2JG+n7pjfpJ+X1Ee2bOtA4ZO39P9/FTEtJUXt+Ivqw=
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										53
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/int-bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										53
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/int-bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEizCCA/agAwIBAgIIeM7v534l+W0wCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT
 | 
			
		||||
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv
 | 
			
		||||
MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG
 | 
			
		||||
A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDA0MTEyMTIyMzdaFw0xOTA0MTEyMTI3
 | 
			
		||||
MzdaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE
 | 
			
		||||
CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET
 | 
			
		||||
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j
 | 
			
		||||
b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL
 | 
			
		||||
AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng
 | 
			
		||||
xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW
 | 
			
		||||
RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu
 | 
			
		||||
u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU
 | 
			
		||||
mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0
 | 
			
		||||
APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys
 | 
			
		||||
sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT
 | 
			
		||||
7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7
 | 
			
		||||
STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow
 | 
			
		||||
TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND
 | 
			
		||||
DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GDMIGAMA4GA1UdDwEB/wQEAwIApDAS
 | 
			
		||||
BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH
 | 
			
		||||
EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAaBgNVHREEEzARgg9j
 | 
			
		||||
ZnNzbC1pbnRlci5jb20wCwYJKoZIhvcNAQELA4GBABqJOYgV+qEgkG/BIgsGaJ/Z
 | 
			
		||||
Neey0x0MwxPvA87e24GiYxYXX8ypR2DfLtuSjYfT0PVOWI5+3o9b3wnHhOu0aVe8
 | 
			
		||||
YK/7XUWOakt8Jv/fE0fGs4Ps5IeMynWBgwrf/6IQWEfnf/1siCrTf0yUEn0PMGu6
 | 
			
		||||
q2sLytoPYeibTYLuP1ED
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEbjCCAligAwIBAgIIeHSbZwALpoAwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
 | 
			
		||||
EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp
 | 
			
		||||
bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
 | 
			
		||||
cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwNDExMjEy
 | 
			
		||||
MjM4WhcNMTkwNDExMjEyNzM4WjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
 | 
			
		||||
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
 | 
			
		||||
DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs
 | 
			
		||||
b3VkZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGw
 | 
			
		||||
f3F0XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73P
 | 
			
		||||
IXGyfNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GDMIGA
 | 
			
		||||
MA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB
 | 
			
		||||
+YoiUjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOS
 | 
			
		||||
FHsHEDAaBgNVHREEEzARgg9jZnNzbC1pbnRlci5jb20wCwYJKoZIhvcNAQELA4IC
 | 
			
		||||
AQCaj2i8wr9r3FS8Tw5QHD+tPmryrHsiLlERVanTif9kt/fRc1/hm/pv2lTLK8kK
 | 
			
		||||
U5Eti1jCB2T/DQGj4Z/amRndasXpUb5wTtMb9V6jN4pRfgw+C5ska9o5zFrIGJF0
 | 
			
		||||
GbSe1VVUedJ1LH3US3a79eVGmyAwcfTRMNhn+e+uYky2VYCQIEGGQ8rZAM3TveoT
 | 
			
		||||
N8J7Lqwtuo3DWz0IYx60DUvabpqJ+9Dl6rhTvTfyYvQK4vl2xApGf4Uo87JbNQfq
 | 
			
		||||
q40UXfBtMaAvIPEKCyTdOVVDrfgW0DQTl7wS+Z3p6kNm0NMI53TFTbgIuU9QiPPB
 | 
			
		||||
I5NdqISEPFW/HS5q0+zR1KdG4EmEjmpCX78s+uviHpHQloWQT9ov4KbXbf8y5Xso
 | 
			
		||||
lv+2gcd5TVjYxPRbo3SMtGRQho5uq2BNy6Q0K0//3OE+X+v+ZDi8n4MU3uA7dGGA
 | 
			
		||||
7uAUZOYPzNKS7ryW3h4PZIfiI5Fv9tBNnu9O3I2UH6fHNFQQLzJPCXertPmrORjP
 | 
			
		||||
EyCNCOhfsNwLd5Qq53cDbG1mkZro/xKDvAOx2LQcGFtmx4v1NXI204V50aSzy8vY
 | 
			
		||||
vQnM0gEY/YxoCq3wSjc9yeUftyv2LIgJvuXjkeHkV7gQQ+jx/HY6J7fnJGSzKMKp
 | 
			
		||||
/GPaPCNKvCY/72ik2gbmdvLbaRGeVJ07JO46YWEUrGb/1A==
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										39
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/leaf.badkey
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										39
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/leaf.badkey
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIG5AIBAAKCAYEA9xYBDoV2tPx8lqZ/bH/wLvoPsg1/CXeknvRcNuxw1gu6c3IJ
 | 
			
		||||
BrKZlkFtiU6Y8FADiUBOVab/Y0cQ/9EdeB2srPH4M5KNiPdWZPgxARWnRq5Ez8pv
 | 
			
		||||
VASP2E2Zya1UnH5iJBau8e6SwBl8UaXnGwcA+CUv+FXcZtdoFh0Lqt3AdItQOkHV
 | 
			
		||||
jSE6Cfiv5lsSW0ikMcoHFOHNps4/9A4A/griT5lRDqQIycN7WD2k4+aKVreCWxbS
 | 
			
		||||
teU35yIDJV6PGUtw8k41arJ+kwuwYM3+YklR0Dsj0RxXn07oLqnf6IeNUogGhNVO
 | 
			
		||||
7RvLdpfvrhlevHVXmmYj40fkGjU15KkZOKigMw/gDInI6Sc2jp8oPX9tjkaQYkF2
 | 
			
		||||
t7AWOq01lh5TleMIoBFUqVcy+X/qejla0JaKCEyt/fiPUo7/SgucyFl8GrKfSdEL
 | 
			
		||||
UOKx5Vr2ZZ48QSfIlXle+tGtFD0AYUsO0ud0wclW5C+g8E27raTuR4RaZOj8/pmB
 | 
			
		||||
7XNDszwxQ/97dBRpAgMBAAECggGAcWoWPhYg8N5cScJPBvyKwOVjQvVS9IOIerXr
 | 
			
		||||
hgJtoLJteQRFBGACg6ewobAEH3p6xQtRaZtn6qf6M5JHFpV4Z0ICDZodgVsWuu35
 | 
			
		||||
gGfyCk1/pGllRIl7hWvJRXtcNSEF507KKp65mZeZKtkeBZfnZ/+Zz0GKE2KYkl3u
 | 
			
		||||
txVme5he0P7bCRbRTzZpdzEicegcBgaXzYwAG6rcTCgJaJKSYrsbK787kXE7MrvI
 | 
			
		||||
7hsqMLe3DByjx35ZdKx2CTcoNBId9RODWnPpANVrlNv7kbaZRqd5OI8b7JfblFsq
 | 
			
		||||
F6vCzvDq+Quc8ID1zxRZv761pexejtDzghgQy7X2EVvMlHh4//wErgq6WfPjwyvU
 | 
			
		||||
/zZczO0L/c1XwwkfBU6Yf6UuYCKngwifgvb7aGU4/aGNcD5SHRITwCHK/E9JrkR8
 | 
			
		||||
pkqerMxsf9uP5FxGdwOm1k77Lkap7Kx2Utt5l7stOY0fFUFz1YQdAHJUzhmbP3Zy
 | 
			
		||||
C+TeX2/9+CudXM1parW7HQRlZeMJAoHBAP545khACfRvUWpxdQohp1Ol0FuDosYg
 | 
			
		||||
NC75q12T8ovllx8Qly3aafJdd0NTvFmrBkBPTL3pCUWCyGZh6/E00fUL4dtD3zwz
 | 
			
		||||
QUbm6hWGTgKHdeLLdae2wxcZ/NqmTvpY9o/p4jS9+StRKQtdsftLKCmRv7wfYkju
 | 
			
		||||
UT7O+gRyGat/Rqpr9cTSKBXHUT+WJlITDrwk5QdydF7eKzLT8DROgcRRE1+FMJkj
 | 
			
		||||
pO5ChuAxZr0Q0fISRm9Lu7aJ3H8QFfboGwKBwQD4kcCkZvRdz8BQsOsyHQ3SlGhx
 | 
			
		||||
5nwA7SPadXtfnpoW0ZlEdHwkPJzU1Z50z1ulEQymBTARPUQ4s28MQt8NXuRzHBrW
 | 
			
		||||
PMUGgsspzT6FjiskhUc8k9PAZbEJE/axLKK2qSKktGuZj+VFih/9XPPTX4xSzlOg
 | 
			
		||||
ntJEr2tc3TIv+JEOuJX6VT2URFLXgdOHXxAejS0DTGIg1aB4VGQpWzfbcJ6Cyf11
 | 
			
		||||
YyoyYWA25wdw7sB9kDHsd0Ej0mld5+l8JOd8hcsCgcA9jCpOcUa3GzF66EQhljAt
 | 
			
		||||
WB6D89urxeA5OGPNN1pjob0iY1XdXkVfvGF7JEaa/XV+mm96Q2HdsRsdQDPb3CWn
 | 
			
		||||
+h6/dLQKkG8KYhFd8WTu0aqelw026kpXTQ7OJ4lUna3M8wmmLgiVBIVD3X6NxAjL
 | 
			
		||||
vRe9vW19LD70TQVFi/9PbnI+B+yilR3i3pl1IrDUCw32TYojefhRdbTHD2G6lP5n
 | 
			
		||||
6CAia0ls0KU0h1yt3uT1d5r/zJHCm3OkW8W76b0WQd8CgcEAh0czk4WgiomtPXz7
 | 
			
		||||
k3tycV9pdEuewxZMQ/FaIpD7hV2uzy2h/kqqg756jVHoq24a9yOtpEQ2o7Erx32B
 | 
			
		||||
TRKOvALYrC3IgKGgFfDojODxo9+RBGvjezsc3TbrNEN5jnWAMCkswhcpDO5+OHJl
 | 
			
		||||
FG1UviAiLTEieFUL1i9fx/G8aEmW/fV0HQQOHdE/INZgvG/Sxo/Ee+AnhDVRiZxm
 | 
			
		||||
StwAuGdbtI4ygday+U5Eo3acdfmK4gmI/wjdZUj4riKbhQ5/AoHBAI0yzo+PIFi6
 | 
			
		||||
HjNYVoC7rZ39oQ0YCrEWrui+DRdEjnjec31Jw02AtKnv5swpDDHjgnIcd9ciQY48
 | 
			
		||||
rk7eC6IkVrL9hOxUzC9YQZX/2MBiOLjUkDkSLt+d5PL0OXiSg1O4fGJdGiVPF0Fc
 | 
			
		||||
sF9p1UNEfGvXjzUB3ay0kMyCLitNe1BCvJlYXdSV9YmAMNvguE7TNU3OPiVv65PK
 | 
			
		||||
6OndznX41Pw7OlnLaq1sFQcYBmf5E7QSKYP+4HeV89Sc824VlCNxwA==
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/leaf.key
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/leaf.key
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEpAIBAAKCAQEA0C6SSsXfuse2IV8+6hSYqSPQdoQwZ5BYQnSxuKylArCrMXx8
 | 
			
		||||
JGHrJP6Pj7GxRmH40v9u9VwZvcrQOm8yUTuzAEf2Kd3uvXmVKJb2vc0BopsflpSE
 | 
			
		||||
OLEuddTSHlHgdVHylqpbzB7ZrmyXXuWTtTFEaGmPVUmWcOBOy6pc/7hZv7HkTjaH
 | 
			
		||||
LQu/uohic/NjO0oJaaUwds6muwTCNSmMvtvoP51pyQJeuZjYIoWnnu+/DbtZYmH4
 | 
			
		||||
4VbHD0U+uSNKLZa4beWqDq5ZDwQvEVkuLqL331awzgIf0a4bhP+uc1kdWXZ8V+8a
 | 
			
		||||
Bbqtq6g6o9HdrzgNRR+9S3EvEelCrxuWw9FQ3QIDAQABAoIBAQDFQ5vzplQ9lIgM
 | 
			
		||||
T0g6XpHZk8oww0lqmOhI8HKG33Dsf6N4HNE1WGOMhnpaWrH0U1mH9eqaLE9n/Aob
 | 
			
		||||
lMpFFyCin42uVlGm0NJ5x7K+Xsex4POpp8kyPxIbLTJ88HCUOrZ39a1OWd1C3jsA
 | 
			
		||||
/OFdy/VaSsw6sKQRCTsg2amN1o2UibDJYVW47ycv9cwjk/GEzzOSq32a9o6g6Gwd
 | 
			
		||||
g3ycroIaxhDlGjS5l0IZ/ozhN+AS5dYcPgJRsYD/jTBqTSzIW2ePrcheznoRcgLK
 | 
			
		||||
bb+UVQC+PZX8kycCcerPbcGc2YcBpZgmIkCj85+ITFt/BhH7+TSH9G7F8LTKAaJg
 | 
			
		||||
qlYKF14BAoGBAPz8Jx0vAcv/4zIfCckuNy3kVu4PHBTMTBO5+tUg6CZgktRrroiV
 | 
			
		||||
+Zq1lCuj2/Px3Lx9oaUie52iV5xgmEEax77xa1rVezY1PhGSFmngHqfumUJf8EEB
 | 
			
		||||
snlAUpwBHvWU9B9OxKOHRrD9Y9ptXcBK30ZHLJT4t5JvbHVrKZF2J82hAoGBANKp
 | 
			
		||||
ue+dOafhgc1F/ThD2VLuIi6Garf1pqNG3OMugMfieHAmr1RRYWwFErLoijt9dpe9
 | 
			
		||||
gXVecUm1KO4/0ZkR+7YDzUSifXvcizaw+XqjrtFerrz+Yao4gZssFnw/sLc2pbWm
 | 
			
		||||
1DHWxRnmh6MyHEEiA0KxElgutswhP8GIKN7INOG9AoGAR1sD2Upp8lVBiuCQTQtZ
 | 
			
		||||
CvutvUXLwN4C00mQw06dzD1PDNU2jFXo6kcu/MQiBQOCJDQ3RLGeNk8U8QmZyDs6
 | 
			
		||||
fdPwWNWABEEuOZx/7+sEGo/E8KDIzj0hTuvioRf72H7kAHSiKBG+0asW4AQa/mLf
 | 
			
		||||
6R2oKHiipo4BBHluZxXxkiECgYEAuYXnzfH0+LhMi+77VjXKipJVYAvYqDGak2iw
 | 
			
		||||
1xH5MA9uabZn6iXRWkQNd6n7MvEHJBMsk6ScuIDmjwt9FwUTW/R1LeC8CfzsTToG
 | 
			
		||||
O88zAggUczTD5hjlazakhr/AbVmfDh7h+RJferPe+AYFhAbkQDOZKDfbnGIbt+Cl
 | 
			
		||||
va0rhTECgYAFb38TvJmEIzB1/nZ7sKbFmr2pYgzBqspQcprws6gZlWydd4OoTZiv
 | 
			
		||||
QzSBDi3tGt07yJuntVlbuI6qejhFMmonGZuntNTvTZMmx2+W/F8EGByfWpLtB9W5
 | 
			
		||||
S+tx5/0d4MhOYHlt0EcdC7j881swY9LCrc/EOqg1O4BlTJ5+UJer+Q==
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										21
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/leaf.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										21
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/api/testdata/leaf.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIDfDCCAwKgAwIBAgIIUYJhG37C300wCgYIKoZIzj0EAwMwgYwxCzAJBgNVBAYT
 | 
			
		||||
AlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJlMRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2lu
 | 
			
		||||
ZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9y
 | 
			
		||||
bmlhMR0wGwYDVQQDExRjbG91ZGZsYXJlLWludGVyLmNvbTAeFw0xNDA0MTEyMTIy
 | 
			
		||||
MzhaFw0xOTA0MTEyMTI3MzhaMIGLMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xv
 | 
			
		||||
dWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMN
 | 
			
		||||
U2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5pYTEcMBoGA1UEAxMTY2xv
 | 
			
		||||
dWRmbGFyZS1sZWFmLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
 | 
			
		||||
ANAukkrF37rHtiFfPuoUmKkj0HaEMGeQWEJ0sbispQKwqzF8fCRh6yT+j4+xsUZh
 | 
			
		||||
+NL/bvVcGb3K0DpvMlE7swBH9ind7r15lSiW9r3NAaKbH5aUhDixLnXU0h5R4HVR
 | 
			
		||||
8paqW8we2a5sl17lk7UxRGhpj1VJlnDgTsuqXP+4Wb+x5E42hy0Lv7qIYnPzYztK
 | 
			
		||||
CWmlMHbOprsEwjUpjL7b6D+dackCXrmY2CKFp57vvw27WWJh+OFWxw9FPrkjSi2W
 | 
			
		||||
uG3lqg6uWQ8ELxFZLi6i999WsM4CH9GuG4T/rnNZHVl2fFfvGgW6rauoOqPR3a84
 | 
			
		||||
DUUfvUtxLxHpQq8blsPRUN0CAwEAAaOBgTB/MA4GA1UdDwEB/wQEAwIApDASBgNV
 | 
			
		||||
HRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBShnoK2Oquaq/XjlNBMxs5yPTSJvjAf
 | 
			
		||||
BgNVHSMEGDAWgBRB+YoiUjIm34/wBwHdJGE4Wufs/DAZBgNVHREEEjAQgg5jZnNz
 | 
			
		||||
bC1sZWFmLmNvbTAKBggqhkjOPQQDAwNoADBlAjAhMWEJzBwuN5bVACPCAoVPSWI2
 | 
			
		||||
+0DQi4Tu6sBNQl+dsyO+FPyA3+aYc0NgnBwcj+0CMQC7JOdfdWJPZj6rOAXvGV3I
 | 
			
		||||
jGJRHZmu5q5K+9teIK1b9mustpnDJgniKAHtBGecXy4=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,75 @@
 | 
			
		|||
// Package auth implements an interface for providing CFSSL
 | 
			
		||||
// authentication. This is meant to authenticate a client CFSSL to a
 | 
			
		||||
// remote CFSSL in order to prevent unauthorised use of the signature
 | 
			
		||||
// capabilities. This package provides both the interface and a
 | 
			
		||||
// standard HMAC-based implementation.
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/hmac"
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An AuthenticatedRequest contains a request and authentication
 | 
			
		||||
// token. The Provider may determine whether to validate the timestamp
 | 
			
		||||
// and remote address.
 | 
			
		||||
type AuthenticatedRequest struct {
 | 
			
		||||
	// An Authenticator decides whether to use this field.
 | 
			
		||||
	Timestamp     int64  `json:"timestamp,omitempty"`
 | 
			
		||||
	RemoteAddress []byte `json:"remote_address,omitempty"`
 | 
			
		||||
	Token         []byte `json:"token"`
 | 
			
		||||
	Request       []byte `json:"request"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Provider can generate tokens from a request and verify a
 | 
			
		||||
// request. The handling of additional authentication data (such as
 | 
			
		||||
// the IP address) is handled by the concrete type, as is any
 | 
			
		||||
// serialisation and state-keeping.
 | 
			
		||||
type Provider interface {
 | 
			
		||||
	Token(req []byte) (token []byte, err error)
 | 
			
		||||
	Verify(aReq *AuthenticatedRequest) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Standard implements an HMAC-SHA-256 authentication provider. It may
 | 
			
		||||
// be supplied additional data at creation time that will be used as
 | 
			
		||||
// request || additional-data with the HMAC.
 | 
			
		||||
type Standard struct {
 | 
			
		||||
	key []byte
 | 
			
		||||
	ad  []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New generates a new standard authentication provider from the key
 | 
			
		||||
// and additional data. The additional data will be used when
 | 
			
		||||
// generating a new token.
 | 
			
		||||
func New(key string, ad []byte) (*Standard, error) {
 | 
			
		||||
	keyBytes, err := hex.DecodeString(key)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Standard{keyBytes, ad}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Token generates a new authentication token from the request.
 | 
			
		||||
func (p Standard) Token(req []byte) (token []byte, err error) {
 | 
			
		||||
	h := hmac.New(sha256.New, p.key)
 | 
			
		||||
	h.Write(req)
 | 
			
		||||
	h.Write(p.ad)
 | 
			
		||||
	return h.Sum(nil), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Verify determines whether an authenticated request is valid.
 | 
			
		||||
func (p Standard) Verify(ad *AuthenticatedRequest) bool {
 | 
			
		||||
	if ad == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Standard token generation returns no error.
 | 
			
		||||
	token, _ := p.Token(ad.Request)
 | 
			
		||||
	if len(ad.Token) != len(token) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return hmac.Equal(token, ad.Token)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										159
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/auth/auth_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										159
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/auth/auth_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,159 @@
 | 
			
		|||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	testProvider   Provider
 | 
			
		||||
	testProviderAD Provider
 | 
			
		||||
	testKey        = "0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
	testAD         = []byte{1, 2, 3, 4} // IP address 1.2.3.4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	_, err := New("ABC", nil)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("expected failure with improperly-hex-encoded key")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	testProvider, err = New(testKey, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	testProviderAD, err = New(testKey, testAD)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	testRequest1A = &AuthenticatedRequest{
 | 
			
		||||
		Request: []byte(`testing 1 2 3`),
 | 
			
		||||
	}
 | 
			
		||||
	testRequest1B = &AuthenticatedRequest{
 | 
			
		||||
		Request: []byte(`testing 1 2 3`),
 | 
			
		||||
	}
 | 
			
		||||
	testRequest2 = &AuthenticatedRequest{
 | 
			
		||||
		Request: []byte(`testing 3 2 1`),
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Sanity check: can a newly-generated token be verified?
 | 
			
		||||
func TestVerifyTrue(t *testing.T) {
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	testRequest1A.Token, err = testProvider.Token(testRequest1A.Request)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	testRequest1B.Token, err = testProviderAD.Token(testRequest1B.Request)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !testProvider.Verify(testRequest1A) {
 | 
			
		||||
		t.Fatal("failed to verify request 1A")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !testProviderAD.Verify(testRequest1B) {
 | 
			
		||||
		t.Fatal("failed to verify request 1B")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sanity check: ensure that additional data is actually used in
 | 
			
		||||
// verification.
 | 
			
		||||
func TestVerifyAD(t *testing.T) {
 | 
			
		||||
	if testProvider.Verify(testRequest1B) {
 | 
			
		||||
		t.Fatal("no-AD provider verifies request with AD")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if testProviderAD.Verify(testRequest1A) {
 | 
			
		||||
		t.Fatal("AD provider verifies request without AD")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sanity check: verification fails if tokens are not the same length.
 | 
			
		||||
func TestTokenLength(t *testing.T) {
 | 
			
		||||
	token := testRequest1A.Token[:]
 | 
			
		||||
	testRequest1A.Token = testRequest1A.Token[1:]
 | 
			
		||||
 | 
			
		||||
	if testProvider.Verify(testRequest1A) {
 | 
			
		||||
		t.Fatal("invalid token should not be verified")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	testRequest1A.Token = token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sanity check: token fails validation if the request is changed.
 | 
			
		||||
func TestBadRequest(t *testing.T) {
 | 
			
		||||
	testRequest2.Token = testRequest1A.Token
 | 
			
		||||
	if testProvider.Verify(testRequest2) {
 | 
			
		||||
		t.Fatal("bad request should fail verification")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sanity check: a null request should fail to verify.
 | 
			
		||||
func TestNullRequest(t *testing.T) {
 | 
			
		||||
	if testProvider.Verify(nil) {
 | 
			
		||||
		t.Fatal("null request should fail verification")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sanity check: verify a pre-generated authenticated request.
 | 
			
		||||
func TestPreGenerated(t *testing.T) {
 | 
			
		||||
	in, err := ioutil.ReadFile("testdata/authrequest.json")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var req AuthenticatedRequest
 | 
			
		||||
	err = json.Unmarshal(in, &req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !testProvider.Verify(&req) {
 | 
			
		||||
		t.Fatal("failed to verify pre-generated request")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var bmRequest []byte
 | 
			
		||||
 | 
			
		||||
func TestLoadBenchmarkRequest(t *testing.T) {
 | 
			
		||||
	in, err := ioutil.ReadFile("testdata/request.json")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bmRequest = in
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkToken(b *testing.B) {
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		_, err := testProvider.Token(bmRequest)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Fatalf("%v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkVerify(b *testing.B) {
 | 
			
		||||
	token, _ := testProvider.Token(bmRequest)
 | 
			
		||||
	req := &AuthenticatedRequest{
 | 
			
		||||
		Token:   token,
 | 
			
		||||
		Request: bmRequest,
 | 
			
		||||
	}
 | 
			
		||||
	b.ResetTimer()
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		if !testProvider.Verify(req) {
 | 
			
		||||
			b.Fatal("failed to verify request")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/auth/testdata/authrequest.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										1
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/auth/testdata/authrequest.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
{"token": "tSU1WTE/322iXrOBfJSQ9/u1dleqpwUmCj1LXYHw07Y=", "request": "ewoJImhvc3RuYW1lIjogImt5bGVpc29tLm5ldCIsCgkicmVxdWVzdCI6ICItLS0tLUJFR0lOIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQoJICAgIE1JSUQwVENDQWpzQ0FRQXdZREVMTUFrR0ExVUVCaE1DVlZNeEVqQVFCZ05WQkFvVENXUnliM0J6YjI1a1pURVEKCSAgICBNQTRHQTFVRUN4TUhRMFl0UTJoaGRERVdNQlFHQTFVRUJ4TU5VMkZ1SUVaeVlXNWphWE5qYnpFVE1CRUdBMVVFCgkgICAgQ0JNS1EyRnNhV1p2Y201cFlUQ0NBYUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0dQQURDQ0FZb0NnZ0dCQU1jQwoJICAgIEdCbDVMVHJla0dGV2hvdGtkYlorUjFNbG9hcld4UXY5alA0QWVrdDhVT2ljeXBIdkZPNnhPdFN3SG8rcjMyaUUKCSAgICBxblM1eXYvMDFQMk1KdXlxbmRuY1RTTXNPbFQvN242N1RNMDB1MDFLLzljL3NvZ0tFS2pseXBsVFA3eUZkRy9jCgkgICAgT3UvOXFLYi9KYWxkMndFTEZZRTZ4cTJSREZ5eHlpWk9CM2c3WjdGeGE1ZDZhZGZHUndaek50VUw0LzhzK0x5aQoJICAgIHFkdzlJMWZrUWQ2MDRwb1pGTjB3clFzNGxmaFdUVWZnMHJIdWg1d2dHS1AzVnpacGJ0OEZiMXZOamZiSHRvaHgKCSAgICBHMlBDVTZKeStEYzFiU2ZVeldjUW5lbnA4NThXNEY4ejdwRjV5YmRuRlIzMTNIam9zcVhuRzI4eklUck9hZE1UCgkgICAgSGFKNnpPaGdFYWZVT1dYT3pqTm9mRkJGYTJJdUNBVCtJVFJZMXRDL2dxcHhHd0gveXVWTjE5Qkc4VXBuMCtIQQoJICAgIGllMm1LQ0hmU0JBS1QvWGU0dW1QZWF4U2JJcVdzVzhjaytkM2I0b3I5Ulp2NWNaUmNUM29pa0p0K1NRRzY5cFcKCSAgICA0T0FiYitBQnNzL05JdXJpNnowZTdERWVJTDV6bXlTSnFkdFlIZE5ZTjcrK3Y5eEJOc0w0SXNVNklFeTMrUUlECgkgICAgQVFBQm9DNHdMQVlKS29aSWh2Y05BUWtPTVI4d0hUQWJCZ05WSFJFRUZEQVNnaEJqWmk1a2NtOXdjMjl1WkdVdQoJICAgIGJtVjBNQXNHQ1NxR1NJYjNEUUVCREFPQ0FZRUFoTUFxQmlySStrMWFVM2xmQUdRaVNtOHl0T3paaWozODloSXIKCSAgICBuVXA4K1duVHVWVGI4WFozL1YrTDlFblRJbUY2dTF3ZWFqWGQzU3VlNDk1NzBMYlltSXV4QmtHcDUwL0JkVUR6CgkgICAgdUI2eHNoaEpXczEySnhVYjkxSW1tMGJUUncyek1xZXdnYTZmdHpaL0FLNG1zeFFBMlVJYmNXWmRzS2J1TTdzbwoJICAgIEpUZlZXOWlPd3FIdC82NFpqNHRCWmY5THpPRHI3a051S0tMbndqaXpIMTg3eGZJSWhkcmpGOFdTN0g5QVBCMU8KCSAgICBTdUVVRGZxaDBTV1IzbHRXdUF1VVdlbzZTS2NIVnVzeS9HNFlFK1BCeXcxZVY3RzRTYmVHNVowbytHT1VVSy9GCgkgICAgYjU1R21XMXhhNExBcnMxQSt6ZUZidkovQkFwc2JVMmI2V1ZtTmE3V3BIejdXWElGT0p1WUpnRWtWS1BKbkt1cwoJICAgIHFxczNGZ1VxejBadjdUSzhtTWlFVEpvWFpzNnpDdk15c1FldTNKL29qZ3RBanZNaHpRYzZQUy9udk90SmRJZysKCSAgICBIMHFYNDlmaHAxQnJZeXNsYWx6UUlGMCtIMHFTVWV5b1V5VjJ3YkxCQUxhcHhNZnZUVmxoTnduYWN0Y0tReHE0CgkgICAgK3dUKzJQVEowYk0vNUFWMFRPMVNQVDBBVmlKaAoJICAgIC0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLSIsCgkicHJvZmlsZSI6ICIiLAoJInJlbW90ZSI6ICIiLAoJImxhYmVsIjogInByaW1hcnkiCn0KCg=="}
 | 
			
		||||
							
								
								
									
										30
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/auth/testdata/request.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										30
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/auth/testdata/request.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
{
 | 
			
		||||
	"hostname": "kyleisom.net",
 | 
			
		||||
	"request": "-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
	    MIID0TCCAjsCAQAwYDELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCWRyb3Bzb25kZTEQ
 | 
			
		||||
	    MA4GA1UECxMHQ0YtQ2hhdDEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UE
 | 
			
		||||
	    CBMKQ2FsaWZvcm5pYTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAMcC
 | 
			
		||||
	    GBl5LTrekGFWhotkdbZ+R1MloarWxQv9jP4Aekt8UOicypHvFO6xOtSwHo+r32iE
 | 
			
		||||
	    qnS5yv/01P2MJuyqndncTSMsOlT/7n67TM00u01K/9c/sogKEKjlyplTP7yFdG/c
 | 
			
		||||
	    Ou/9qKb/Jald2wELFYE6xq2RDFyxyiZOB3g7Z7Fxa5d6adfGRwZzNtUL4/8s+Lyi
 | 
			
		||||
	    qdw9I1fkQd604poZFN0wrQs4lfhWTUfg0rHuh5wgGKP3VzZpbt8Fb1vNjfbHtohx
 | 
			
		||||
	    G2PCU6Jy+Dc1bSfUzWcQnenp858W4F8z7pF5ybdnFR313HjosqXnG28zITrOadMT
 | 
			
		||||
	    HaJ6zOhgEafUOWXOzjNofFBFa2IuCAT+ITRY1tC/gqpxGwH/yuVN19BG8Upn0+HA
 | 
			
		||||
	    ie2mKCHfSBAKT/Xe4umPeaxSbIqWsW8ck+d3b4or9RZv5cZRcT3oikJt+SQG69pW
 | 
			
		||||
	    4OAbb+ABss/NIuri6z0e7DEeIL5zmySJqdtYHdNYN7++v9xBNsL4IsU6IEy3+QID
 | 
			
		||||
	    AQABoC4wLAYJKoZIhvcNAQkOMR8wHTAbBgNVHREEFDASghBjZi5kcm9wc29uZGUu
 | 
			
		||||
	    bmV0MAsGCSqGSIb3DQEBDAOCAYEAhMAqBirI+k1aU3lfAGQiSm8ytOzZij389hIr
 | 
			
		||||
	    nUp8+WnTuVTb8XZ3/V+L9EnTImF6u1weajXd3Sue49570LbYmIuxBkGp50/BdUDz
 | 
			
		||||
	    uB6xshhJWs12JxUb91Imm0bTRw2zMqewga6ftzZ/AK4msxQA2UIbcWZdsKbuM7so
 | 
			
		||||
	    JTfVW9iOwqHt/64Zj4tBZf9LzODr7kNuKKLnwjizH187xfIIhdrjF8WS7H9APB1O
 | 
			
		||||
	    SuEUDfqh0SWR3ltWuAuUWeo6SKcHVusy/G4YE+PByw1eV7G4SbeG5Z0o+GOUUK/F
 | 
			
		||||
	    b55GmW1xa4LArs1A+zeFbvJ/BApsbU2b6WVmNa7WpHz7WXIFOJuYJgEkVKPJnKus
 | 
			
		||||
	    qqs3FgUqz0Zv7TK8mMiETJoXZs6zCvMysQeu3J/ojgtAjvMhzQc6PS/nvOtJdIg+
 | 
			
		||||
	    H0qX49fhp1BrYyslalzQIF0+H0qSUeyoUyV2wbLBALapxMfvTVlhNwnactcKQxq4
 | 
			
		||||
	    +wT+2PTJ0bM/5AV0TO1SPT0AViJh
 | 
			
		||||
	    -----END CERTIFICATE REQUEST-----",
 | 
			
		||||
	"profile": "",
 | 
			
		||||
	"remote": "",
 | 
			
		||||
	"label": "primary"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										419
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/config.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										419
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/config.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,419 @@
 | 
			
		|||
// Package config contains the configuration logic for CF-SSL.
 | 
			
		||||
package config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/asn1"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
 | 
			
		||||
	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A SigningProfile stores information that the CA needs to store
 | 
			
		||||
// signature policy.
 | 
			
		||||
type SigningProfile struct {
 | 
			
		||||
	Usage          []string  `json:"usages"`
 | 
			
		||||
	IssuerURL      []string  `json:"issuer_urls"`
 | 
			
		||||
	OCSP           string    `json:"ocsp_url"`
 | 
			
		||||
	CRL            string    `json:"crl_url"`
 | 
			
		||||
	CA             bool      `json:"is_ca"`
 | 
			
		||||
	PolicyStrings  []string  `json:"policies"`
 | 
			
		||||
	OCSPNoCheck    bool      `json:"ocsp_no_check"`
 | 
			
		||||
	ExpiryString   string    `json:"expiry"`
 | 
			
		||||
	BackdateString string    `json:"backdate"`
 | 
			
		||||
	AuthKeyName    string    `json:"auth_key"`
 | 
			
		||||
	RemoteName     string    `json:"remote"`
 | 
			
		||||
	NotBefore      time.Time `json:"not_before"`
 | 
			
		||||
	NotAfter       time.Time `json:"not_after"`
 | 
			
		||||
 | 
			
		||||
	Policies     []asn1.ObjectIdentifier
 | 
			
		||||
	Expiry       time.Duration
 | 
			
		||||
	Backdate     time.Duration
 | 
			
		||||
	Provider     auth.Provider
 | 
			
		||||
	RemoteServer string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseObjectIdentifier(oidString string) (oid asn1.ObjectIdentifier, err error) {
 | 
			
		||||
	validOID, err := regexp.MatchString("\\d(\\.\\d+)*", oidString)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if !validOID {
 | 
			
		||||
		err = errors.New("Invalid OID")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	segments := strings.Split(oidString, ".")
 | 
			
		||||
	oid = make(asn1.ObjectIdentifier, len(segments))
 | 
			
		||||
	for i, intString := range segments {
 | 
			
		||||
		oid[i], err = strconv.Atoi(intString)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const timeFormat = "2006-01-02T15:04:05"
 | 
			
		||||
 | 
			
		||||
// populate is used to fill in the fields that are not in JSON
 | 
			
		||||
//
 | 
			
		||||
// First, the ExpiryString parameter is needed to parse
 | 
			
		||||
// expiration timestamps from JSON. The JSON decoder is not able to
 | 
			
		||||
// decode a string time duration to a time.Duration, so this is called
 | 
			
		||||
// when loading the configuration to properly parse and fill out the
 | 
			
		||||
// Expiry parameter.
 | 
			
		||||
// This function is also used to create references to the auth key
 | 
			
		||||
// and default remote for the profile.
 | 
			
		||||
// It returns true if ExpiryString is a valid representation of a
 | 
			
		||||
// time.Duration, and the AuthKeyString and RemoteName point to
 | 
			
		||||
// valid objects. It returns false otherwise.
 | 
			
		||||
func (p *SigningProfile) populate(cfg *Config) error {
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("can't parse nil profile"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	if p.RemoteName == "" {
 | 
			
		||||
		log.Debugf("parse expiry in profile")
 | 
			
		||||
		if p.ExpiryString == "" {
 | 
			
		||||
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("empty expiry string"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dur, err := time.ParseDuration(p.ExpiryString)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log.Debugf("expiry is valid")
 | 
			
		||||
		p.Expiry = dur
 | 
			
		||||
 | 
			
		||||
		if p.BackdateString != "" {
 | 
			
		||||
			dur, err = time.ParseDuration(p.BackdateString)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			p.Backdate = dur
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !p.NotBefore.IsZero() && !p.NotAfter.IsZero() && p.NotAfter.Before(p.NotBefore) {
 | 
			
		||||
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(p.PolicyStrings) > 0 {
 | 
			
		||||
			p.Policies = make([]asn1.ObjectIdentifier, len(p.PolicyStrings))
 | 
			
		||||
			for i, oidString := range p.PolicyStrings {
 | 
			
		||||
				p.Policies[i], err = parseObjectIdentifier(oidString)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Debug("match remote in profile to remotes section")
 | 
			
		||||
		if remote := cfg.Remotes[p.RemoteName]; remote != "" {
 | 
			
		||||
			if err := p.updateRemote(remote); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
 | 
			
		||||
				errors.New("failed to find remote in remotes section"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p.AuthKeyName != "" {
 | 
			
		||||
		log.Debug("match auth key in profile to auth_keys section")
 | 
			
		||||
		if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok == true {
 | 
			
		||||
			if key.Type == "standard" {
 | 
			
		||||
				p.Provider, err = auth.New(key.Key, nil)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Debugf("failed to create new standard auth provider: %v", err)
 | 
			
		||||
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
 | 
			
		||||
						errors.New("failed to create new standard auth provider"))
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Debugf("unknown authentication type %v", key.Type)
 | 
			
		||||
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
 | 
			
		||||
					errors.New("unknown authentication type"))
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
 | 
			
		||||
				errors.New("failed to find auth_key in auth_keys section"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// updateRemote takes a signing profile and initializes the remote server object
 | 
			
		||||
// to the hostname:port combination sent by remote
 | 
			
		||||
func (p *SigningProfile) updateRemote(remote string) error {
 | 
			
		||||
	if remote != "" {
 | 
			
		||||
		p.RemoteServer = remote
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OverrideRemotes takes a signing configuration and updates the remote server object
 | 
			
		||||
// to the hostname:port combination sent by remote
 | 
			
		||||
func (p *Signing) OverrideRemotes(remote string) error {
 | 
			
		||||
	if remote != "" {
 | 
			
		||||
		var err error
 | 
			
		||||
		for _, profile := range p.Profiles {
 | 
			
		||||
			err = profile.updateRemote(remote)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		err = p.Default.updateRemote(remote)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NeedsRemoteSigner returns true if one of the profiles has a remote set
 | 
			
		||||
func (p *Signing) NeedsRemoteSigner() bool {
 | 
			
		||||
	for _, profile := range p.Profiles {
 | 
			
		||||
		if profile.RemoteName != "" {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if p.Default.RemoteName != "" {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NeedsLocalSigner returns true if one of the profiles doe not have a remote set
 | 
			
		||||
func (p *Signing) NeedsLocalSigner() bool {
 | 
			
		||||
	for _, profile := range p.Profiles {
 | 
			
		||||
		if profile.RemoteName == "" {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if p.Default.RemoteName == "" {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Usages parses the list of key uses in the profile, translating them
 | 
			
		||||
// to a list of X.509 key usages and extended key usages.  The unknown
 | 
			
		||||
// uses are collected into a slice that is also returned.
 | 
			
		||||
func (p *SigningProfile) Usages() (ku x509.KeyUsage, eku []x509.ExtKeyUsage, unk []string) {
 | 
			
		||||
	for _, keyUse := range p.Usage {
 | 
			
		||||
		if kuse, ok := KeyUsage[keyUse]; ok {
 | 
			
		||||
			ku |= kuse
 | 
			
		||||
		} else if ekuse, ok := ExtKeyUsage[keyUse]; ok {
 | 
			
		||||
			eku = append(eku, ekuse)
 | 
			
		||||
		} else {
 | 
			
		||||
			unk = append(unk, keyUse)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A valid profile must be a valid local profile or a valid remote profile.
 | 
			
		||||
// A valid local profile has defined at least key usages to be used, and a
 | 
			
		||||
// valid local default profile has defined at least a default expiration.
 | 
			
		||||
// A valid remote profile (default or not) has remote signer initialized.
 | 
			
		||||
// In addition, a remote profile must has a valid auth provider if auth
 | 
			
		||||
// key defined.
 | 
			
		||||
func (p *SigningProfile) validProfile(isDefault bool) bool {
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p.RemoteName != "" {
 | 
			
		||||
		log.Debugf("validate remote profile")
 | 
			
		||||
 | 
			
		||||
		if p.RemoteServer == "" {
 | 
			
		||||
			log.Debugf("invalid remote profile: no remote signer specified")
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if p.AuthKeyName != "" && p.Provider == nil {
 | 
			
		||||
			log.Debugf("invalid remote profile: auth key name is defined but no auth provider is set")
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Debugf("validate local profile")
 | 
			
		||||
		if !isDefault {
 | 
			
		||||
			if len(p.Usage) == 0 {
 | 
			
		||||
				log.Debugf("invalid local profile: no usages specified")
 | 
			
		||||
				return false
 | 
			
		||||
			} else if _, _, unk := p.Usages(); len(unk) == len(p.Usage) {
 | 
			
		||||
				log.Debugf("invalid local profile: no valid usages")
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if p.Expiry == 0 {
 | 
			
		||||
				log.Debugf("invalid local profile: no expiry set")
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Debugf("profile is valid")
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Signing codifies the signature configuration policy for a CA.
 | 
			
		||||
type Signing struct {
 | 
			
		||||
	Profiles map[string]*SigningProfile `json:"profiles"`
 | 
			
		||||
	Default  *SigningProfile            `json:"default"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Config stores configuration information for the CA.
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Signing  *Signing           `json:"signing"`
 | 
			
		||||
	AuthKeys map[string]AuthKey `json:"auth_keys,omitempty"`
 | 
			
		||||
	Remotes  map[string]string  `json:"remotes,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Valid ensures that Config is a valid configuration. It should be
 | 
			
		||||
// called immediately after parsing a configuration file.
 | 
			
		||||
func (c *Config) Valid() bool {
 | 
			
		||||
	return c.Signing.Valid()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Valid checks the signature policies, ensuring they are valid
 | 
			
		||||
// policies. A policy is valid if it has defined at least key usages
 | 
			
		||||
// to be used, and a valid default profile has defined at least a
 | 
			
		||||
// default expiration.
 | 
			
		||||
func (p *Signing) Valid() bool {
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Debugf("validating configuration")
 | 
			
		||||
	if !p.Default.validProfile(true) {
 | 
			
		||||
		log.Debugf("default profile is invalid")
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, sp := range p.Profiles {
 | 
			
		||||
		if !sp.validProfile(false) {
 | 
			
		||||
			log.Debugf("invalid profile")
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KeyUsage contains a mapping of string names to key usages.
 | 
			
		||||
var KeyUsage = map[string]x509.KeyUsage{
 | 
			
		||||
	"signing":             x509.KeyUsageDigitalSignature,
 | 
			
		||||
	"digital signature":   x509.KeyUsageDigitalSignature,
 | 
			
		||||
	"content committment": x509.KeyUsageContentCommitment,
 | 
			
		||||
	"key encipherment":    x509.KeyUsageKeyEncipherment,
 | 
			
		||||
	"data encipherment":   x509.KeyUsageDataEncipherment,
 | 
			
		||||
	"cert sign":           x509.KeyUsageCertSign,
 | 
			
		||||
	"crl sign":            x509.KeyUsageCRLSign,
 | 
			
		||||
	"encipher only":       x509.KeyUsageEncipherOnly,
 | 
			
		||||
	"decipher only":       x509.KeyUsageDecipherOnly,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExtKeyUsage contains a mapping of string names to extended key
 | 
			
		||||
// usages.
 | 
			
		||||
var ExtKeyUsage = map[string]x509.ExtKeyUsage{
 | 
			
		||||
	"any":              x509.ExtKeyUsageAny,
 | 
			
		||||
	"server auth":      x509.ExtKeyUsageServerAuth,
 | 
			
		||||
	"client auth":      x509.ExtKeyUsageClientAuth,
 | 
			
		||||
	"code signing":     x509.ExtKeyUsageCodeSigning,
 | 
			
		||||
	"email protection": x509.ExtKeyUsageEmailProtection,
 | 
			
		||||
	"s/mime":           x509.ExtKeyUsageEmailProtection,
 | 
			
		||||
	"ipsec end system": x509.ExtKeyUsageIPSECEndSystem,
 | 
			
		||||
	"ipsec tunnel":     x509.ExtKeyUsageIPSECTunnel,
 | 
			
		||||
	"ipsec user":       x509.ExtKeyUsageIPSECUser,
 | 
			
		||||
	"timestamping":     x509.ExtKeyUsageTimeStamping,
 | 
			
		||||
	"ocsp signing":     x509.ExtKeyUsageOCSPSigning,
 | 
			
		||||
	"microsoft sgc":    x509.ExtKeyUsageMicrosoftServerGatedCrypto,
 | 
			
		||||
	"netscape sgc":     x509.ExtKeyUsageNetscapeServerGatedCrypto,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An AuthKey contains an entry for a key used for authentication.
 | 
			
		||||
type AuthKey struct {
 | 
			
		||||
	// Type contains information needed to select the appropriate
 | 
			
		||||
	// constructor. For example, "standard" for HMAC-SHA-256,
 | 
			
		||||
	// "standard-ip" for HMAC-SHA-256 incorporating the client's
 | 
			
		||||
	// IP.
 | 
			
		||||
	Type string `json:"type"`
 | 
			
		||||
	// Key contains the key information, such as a hex-encoded
 | 
			
		||||
	// HMAC key.
 | 
			
		||||
	Key string `json:"key"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultConfig returns a default configuration specifying basic key
 | 
			
		||||
// usage and a 1 year expiration time. The key usages chosen are
 | 
			
		||||
// signing, key encipherment, client auth and server auth.
 | 
			
		||||
func DefaultConfig() *SigningProfile {
 | 
			
		||||
	d := helpers.OneYear
 | 
			
		||||
	return &SigningProfile{
 | 
			
		||||
		Usage:        []string{"signing", "key encipherment", "server auth", "client auth"},
 | 
			
		||||
		Expiry:       d,
 | 
			
		||||
		ExpiryString: "8760h",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadFile attempts to load the configuration file stored at the path
 | 
			
		||||
// and returns the configuration. On error, it returns nil.
 | 
			
		||||
func LoadFile(path string) (*Config, error) {
 | 
			
		||||
	log.Debugf("loading configuration file from %s", path)
 | 
			
		||||
	if path == "" {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body, err := ioutil.ReadFile(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return LoadConfig(body)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadConfig attempts to load the configuration from a byte slice.
 | 
			
		||||
// On error, it returns nil.
 | 
			
		||||
func LoadConfig(config []byte) (*Config, error) {
 | 
			
		||||
	var cfg = &Config{}
 | 
			
		||||
	err := json.Unmarshal(config, &cfg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("failed to unmarshal configuration"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cfg.Signing.Default == nil {
 | 
			
		||||
		log.Debugf("no default given: using default config")
 | 
			
		||||
		cfg.Signing.Default = DefaultConfig()
 | 
			
		||||
	} else {
 | 
			
		||||
		if err := cfg.Signing.Default.populate(cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k := range cfg.Signing.Profiles {
 | 
			
		||||
		if err := cfg.Signing.Profiles[k].populate(cfg); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !cfg.Valid() {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid configuration"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Debugf("configuration ok")
 | 
			
		||||
	return cfg, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										337
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/config_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										337
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/config_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,337 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var expiry = 1 * time.Minute
 | 
			
		||||
 | 
			
		||||
var invalidProfileConfig = &Config{
 | 
			
		||||
	Signing: &Signing{
 | 
			
		||||
		Profiles: map[string]*SigningProfile{
 | 
			
		||||
			"invalid": {
 | 
			
		||||
				Usage:  []string{"wiretapping"},
 | 
			
		||||
				Expiry: expiry,
 | 
			
		||||
			},
 | 
			
		||||
			"empty": {},
 | 
			
		||||
		},
 | 
			
		||||
		Default: &SigningProfile{
 | 
			
		||||
			Usage:  []string{"digital signature"},
 | 
			
		||||
			Expiry: expiry,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var invalidDefaultConfig = &Config{
 | 
			
		||||
	Signing: &Signing{
 | 
			
		||||
		Profiles: map[string]*SigningProfile{
 | 
			
		||||
			"key usage": {
 | 
			
		||||
				Usage: []string{"digital signature"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Default: &SigningProfile{
 | 
			
		||||
			Usage: []string{"s/mime"},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var validConfig = &Config{
 | 
			
		||||
	Signing: &Signing{
 | 
			
		||||
		Profiles: map[string]*SigningProfile{
 | 
			
		||||
			"valid": {
 | 
			
		||||
				Usage:  []string{"digital signature"},
 | 
			
		||||
				Expiry: expiry,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Default: &SigningProfile{
 | 
			
		||||
			Usage:  []string{"digital signature"},
 | 
			
		||||
			Expiry: expiry,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var validMixedConfig = `
 | 
			
		||||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"auth_key": "sample",
 | 
			
		||||
				"remote": "localhost"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"sample": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
var validMinimalRemoteConfig = `
 | 
			
		||||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"default": {
 | 
			
		||||
			"auth_key": "sample",
 | 
			
		||||
			"remote": "localhost"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"sample": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
var validMinimalLocalConfig = `
 | 
			
		||||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
func TestInvalidProfile(t *testing.T) {
 | 
			
		||||
	if invalidProfileConfig.Signing.Profiles["invalid"].validProfile(false) {
 | 
			
		||||
		t.Fatal("invalid profile accepted as valid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if invalidProfileConfig.Signing.Profiles["empty"].validProfile(false) {
 | 
			
		||||
		t.Fatal("invalid profile accepted as valid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if invalidProfileConfig.Valid() {
 | 
			
		||||
		t.Fatal("invalid config accepted as valid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !invalidProfileConfig.Signing.Profiles["invalid"].validProfile(true) {
 | 
			
		||||
		t.Fatal("invalid profile should be a valid default profile")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemoteProfiles(t *testing.T) {
 | 
			
		||||
	var validRemoteProfile = &SigningProfile{
 | 
			
		||||
		RemoteName:   "localhost",
 | 
			
		||||
		RemoteServer: "localhost:8080",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var invalidRemoteProfile = &SigningProfile{
 | 
			
		||||
		RemoteName: "localhost",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var invalidRemoteAuthProfile = &SigningProfile{
 | 
			
		||||
		RemoteName:   "localhost",
 | 
			
		||||
		RemoteServer: "localhost:8080",
 | 
			
		||||
		AuthKeyName:  "blahblah",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !validRemoteProfile.validProfile(true) ||
 | 
			
		||||
		!validRemoteProfile.validProfile(false) {
 | 
			
		||||
		t.Fatal("valid remote profile is rejected.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if invalidRemoteProfile.validProfile(true) ||
 | 
			
		||||
		invalidRemoteProfile.validProfile(false) {
 | 
			
		||||
		t.Fatal("invalid remote profile is accepted.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if invalidRemoteAuthProfile.validProfile(true) ||
 | 
			
		||||
		invalidRemoteAuthProfile.validProfile(false) {
 | 
			
		||||
		t.Fatal("invalid remote profile is accepted.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestInvalidDefault(t *testing.T) {
 | 
			
		||||
	if invalidDefaultConfig.Signing.Default.validProfile(true) {
 | 
			
		||||
		t.Fatal("invalid default accepted as valid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if invalidDefaultConfig.Valid() {
 | 
			
		||||
		t.Fatal("invalid config accepted as valid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !invalidDefaultConfig.Signing.Default.validProfile(false) {
 | 
			
		||||
		t.Fatal("invalid default profile should be a valid profile")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidConfig(t *testing.T) {
 | 
			
		||||
	if !validConfig.Valid() {
 | 
			
		||||
		t.Fatal("Valid config is not valid")
 | 
			
		||||
	}
 | 
			
		||||
	bytes, _ := json.Marshal(validConfig)
 | 
			
		||||
	fmt.Printf("%v", string(bytes))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDefaultConfig(t *testing.T) {
 | 
			
		||||
	if !DefaultConfig().validProfile(false) {
 | 
			
		||||
		t.Fatal("global default signing profile should be a valid profile.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !DefaultConfig().validProfile(true) {
 | 
			
		||||
		t.Fatal("global default signing profile should be a valid default profile")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParse(t *testing.T) {
 | 
			
		||||
	var validProfiles = []*SigningProfile{
 | 
			
		||||
		{
 | 
			
		||||
			ExpiryString: "8760h",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			ExpiryString: "168h",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			ExpiryString: "300s",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var invalidProfiles = []*SigningProfile{
 | 
			
		||||
		nil,
 | 
			
		||||
		{},
 | 
			
		||||
		{
 | 
			
		||||
			ExpiryString: "",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			ExpiryString: "365d",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			ExpiryString: "1y",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			ExpiryString: "one year",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, p := range validProfiles {
 | 
			
		||||
		if p.populate(nil) != nil {
 | 
			
		||||
			t.Fatalf("Failed to parse ExpiryString=%s", p.ExpiryString)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, p := range invalidProfiles {
 | 
			
		||||
		if p.populate(nil) == nil {
 | 
			
		||||
			if p != nil {
 | 
			
		||||
				t.Fatalf("ExpiryString=%s should not be parseable", p.ExpiryString)
 | 
			
		||||
			}
 | 
			
		||||
			t.Fatalf("Nil profile should not be parseable")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadFile(t *testing.T) {
 | 
			
		||||
	validConfigFiles := []string{
 | 
			
		||||
		"testdata/valid_config.json",
 | 
			
		||||
		"testdata/valid_config_auth.json",
 | 
			
		||||
		"testdata/valid_config_no_default.json",
 | 
			
		||||
		"testdata/valid_config_auth_no_default.json",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, configFile := range validConfigFiles {
 | 
			
		||||
		_, err := LoadFile(configFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal("Load valid config file failed.", configFile, "error is ", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestLoadInvalidConfigFile(t *testing.T) {
 | 
			
		||||
	invalidConfigFiles := []string{"", "testdata/no_such_file",
 | 
			
		||||
		"testdata/invalid_default.json",
 | 
			
		||||
		"testdata/invalid_profiles.json",
 | 
			
		||||
		"testdata/invalid_usage.json",
 | 
			
		||||
		"testdata/invalid_config.json",
 | 
			
		||||
		"testdata/invalid_auth.json",
 | 
			
		||||
		"testdata/invalid_auth_bad_key.json",
 | 
			
		||||
		"testdata/invalid_no_auth_keys.json",
 | 
			
		||||
		"testdata/invalid_remote.json",
 | 
			
		||||
		"testdata/invalid_no_remotes.json",
 | 
			
		||||
	}
 | 
			
		||||
	for _, configFile := range invalidConfigFiles {
 | 
			
		||||
		_, err := LoadFile(configFile)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			t.Fatal("Invalid config is loaded.", configFile)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNeedLocalSigner(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	c, err := LoadConfig([]byte(validMixedConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("load valid config failed:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// This signing config needs both local signer and remote signer.
 | 
			
		||||
	if c.Signing.NeedsLocalSigner() != true {
 | 
			
		||||
		t.Fatal("incorrect NeedsLocalSigner().")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.Signing.NeedsRemoteSigner() != true {
 | 
			
		||||
		t.Fatal("incorrect NeedsRemoteSigner()")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	remoteConfig, err := LoadConfig([]byte(validMinimalRemoteConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("Load valid config failed:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if remoteConfig.Signing.NeedsLocalSigner() != false {
 | 
			
		||||
		t.Fatal("incorrect NeedsLocalSigner().")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if remoteConfig.Signing.NeedsRemoteSigner() != true {
 | 
			
		||||
		t.Fatal("incorrect NeedsRemoteSigner().")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	localConfig, err := LoadConfig([]byte(validMinimalLocalConfig))
 | 
			
		||||
	if localConfig.Signing.NeedsLocalSigner() != true {
 | 
			
		||||
		t.Fatal("incorrect NeedsLocalSigner().")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if localConfig.Signing.NeedsRemoteSigner() != false {
 | 
			
		||||
		t.Fatal("incorrect NeedsRemoteSigner().")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOverrideRemotes(t *testing.T) {
 | 
			
		||||
	c, err := LoadConfig([]byte(validMixedConfig))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("load valid config failed:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	host := "localhost:8888"
 | 
			
		||||
	c.Signing.OverrideRemotes(host)
 | 
			
		||||
 | 
			
		||||
	if c.Signing.Default.RemoteServer != host {
 | 
			
		||||
		t.Fatal("should override default profile's RemoteServer")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, p := range c.Signing.Profiles {
 | 
			
		||||
		if p.RemoteServer != host {
 | 
			
		||||
			t.Fatal("failed to override profile's RemoteServer")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_auth.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_auth.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"remote": "localhost",
 | 
			
		||||
				"auth_key": "garbage"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"garbage": {
 | 
			
		||||
			"type":"stadardo",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_auth_bad_key.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_auth_bad_key.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"remote": "localhost",
 | 
			
		||||
				"auth_key": "garbage"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"garbage": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"BAD_KEY"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_config.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										17
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_config.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"usages": ["cert sign"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_default.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										18
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_default.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"usages": ["cert sign"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "invalid_expiry"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_no_auth_keys.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										23
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_no_auth_keys.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"remote": "localhost",
 | 
			
		||||
				"auth_key": "garbage"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_no_remotes.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										24
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_no_remotes.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"auth_key": "garbage",
 | 
			
		||||
				"remote": "localhoster"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"garbage": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_profile.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										18
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_profile.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"usages": ["cert sign"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "invalid_expiry"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_remotes.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_remotes.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"auth_key": "garbage",
 | 
			
		||||
				"remote": "localhoster"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"garbage": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_usage.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										18
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/invalid_usage.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"usages": ["cert sign"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["BAD_USAGE"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										24
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"usages": ["cert sign"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_key": {
 | 
			
		||||
		"garbage": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config_auth.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										29
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config_auth.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"usages": ["cert sign"],
 | 
			
		||||
				"expiry": "720h",
 | 
			
		||||
				"auth_key": "garbage",
 | 
			
		||||
				"remote": "localhost"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"default": {
 | 
			
		||||
			"usages": ["digital signature", "email protection"],
 | 
			
		||||
			"expiry": "8000h"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"garbage": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config_auth_no_default.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										19
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config_auth_no_default.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"auth_key": "garbage",
 | 
			
		||||
				"remote": "localhost"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"garbage": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:8888"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config_no_default.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										14
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/config/testdata/valid_config_no_default.json
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"profiles": {
 | 
			
		||||
			"CA": {
 | 
			
		||||
				"usages": ["cert sign"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			},
 | 
			
		||||
			"email": {
 | 
			
		||||
				"usages": ["s/mime"],
 | 
			
		||||
				"expiry": "720h"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,236 @@
 | 
			
		|||
// Package csr implements certificate requests for CF-SSL.
 | 
			
		||||
package csr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"crypto/x509/pkix"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	curveP256 = 256
 | 
			
		||||
	curveP384 = 384
 | 
			
		||||
	curveP521 = 521
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Name contains the SubjectInfo fields.
 | 
			
		||||
type Name struct {
 | 
			
		||||
	C  string // Country
 | 
			
		||||
	ST string // State
 | 
			
		||||
	L  string // Locality
 | 
			
		||||
	O  string // OrganisationName
 | 
			
		||||
	OU string // OrganisationalUnitName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A KeyRequest contains the algorithm and key size for a new private
 | 
			
		||||
// key.
 | 
			
		||||
type KeyRequest struct {
 | 
			
		||||
	Algo string `json:"algo"`
 | 
			
		||||
	Size int    `json:"size"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The DefaultKeyRequest is used when no key request data is provided
 | 
			
		||||
// in the request. This should be a safe default.
 | 
			
		||||
var DefaultKeyRequest = KeyRequest{
 | 
			
		||||
	Algo: "ecdsa",
 | 
			
		||||
	Size: curveP256,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generate generates a key as specified in the request. Currently,
 | 
			
		||||
// only ECDSA and RSA are supported.
 | 
			
		||||
func (kr *KeyRequest) Generate() (interface{}, error) {
 | 
			
		||||
	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo, kr.Size)
 | 
			
		||||
	switch kr.Algo {
 | 
			
		||||
	case "rsa":
 | 
			
		||||
		if kr.Size < 2048 {
 | 
			
		||||
			return nil, errors.New("RSA key is too weak")
 | 
			
		||||
		}
 | 
			
		||||
		return rsa.GenerateKey(rand.Reader, kr.Size)
 | 
			
		||||
	case "ecdsa":
 | 
			
		||||
		var curve elliptic.Curve
 | 
			
		||||
		switch kr.Size {
 | 
			
		||||
		case curveP256:
 | 
			
		||||
			curve = elliptic.P256()
 | 
			
		||||
		case curveP384:
 | 
			
		||||
			curve = elliptic.P384()
 | 
			
		||||
		case curveP521:
 | 
			
		||||
			curve = elliptic.P521()
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, errors.New("invalid curve")
 | 
			
		||||
		}
 | 
			
		||||
		return ecdsa.GenerateKey(curve, rand.Reader)
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errors.New("invalid algorithm")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SigAlgo returns an appropriate X.509 signature algorithm given the
 | 
			
		||||
// key request's type and size.
 | 
			
		||||
func (kr *KeyRequest) SigAlgo() x509.SignatureAlgorithm {
 | 
			
		||||
	switch kr.Algo {
 | 
			
		||||
	case "rsa":
 | 
			
		||||
		switch {
 | 
			
		||||
		case kr.Size >= 4096:
 | 
			
		||||
			return x509.SHA512WithRSA
 | 
			
		||||
		case kr.Size >= 3072:
 | 
			
		||||
			return x509.SHA384WithRSA
 | 
			
		||||
		case kr.Size >= 2048:
 | 
			
		||||
			return x509.SHA256WithRSA
 | 
			
		||||
		default:
 | 
			
		||||
			return x509.SHA1WithRSA
 | 
			
		||||
		}
 | 
			
		||||
	case "ecdsa":
 | 
			
		||||
		switch {
 | 
			
		||||
		case kr.Size == curveP521:
 | 
			
		||||
			return x509.ECDSAWithSHA512
 | 
			
		||||
		case kr.Size == curveP384:
 | 
			
		||||
			return x509.ECDSAWithSHA384
 | 
			
		||||
		case kr.Size == curveP256:
 | 
			
		||||
			return x509.ECDSAWithSHA256
 | 
			
		||||
		default:
 | 
			
		||||
			return x509.ECDSAWithSHA1
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return x509.UnknownSignatureAlgorithm
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CAConfig is a section used in the requests initialising a new CA.
 | 
			
		||||
type CAConfig struct {
 | 
			
		||||
	PathLength int    `json:"pathlen"`
 | 
			
		||||
	Expiry     string `json:"expiry"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A CertificateRequest encapsulates the API interface to the
 | 
			
		||||
// certificate request functionality.
 | 
			
		||||
type CertificateRequest struct {
 | 
			
		||||
	CN         string
 | 
			
		||||
	Names      []Name      `json:"names"`
 | 
			
		||||
	Hosts      []string    `json:"hosts"`
 | 
			
		||||
	KeyRequest *KeyRequest `json:"key,omitempty"`
 | 
			
		||||
	CA         *CAConfig   `json:"ca,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// appendIf appends to a if s is not an empty string.
 | 
			
		||||
func appendIf(s string, a *[]string) {
 | 
			
		||||
	if s != "" {
 | 
			
		||||
		*a = append(*a, s)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Name returns the PKIX name for the request.
 | 
			
		||||
func (cr *CertificateRequest) Name() pkix.Name {
 | 
			
		||||
	var name pkix.Name
 | 
			
		||||
	name.CommonName = cr.CN
 | 
			
		||||
 | 
			
		||||
	for _, n := range cr.Names {
 | 
			
		||||
		appendIf(n.C, &name.Country)
 | 
			
		||||
		appendIf(n.ST, &name.Province)
 | 
			
		||||
		appendIf(n.L, &name.Locality)
 | 
			
		||||
		appendIf(n.O, &name.Organization)
 | 
			
		||||
		appendIf(n.OU, &name.OrganizationalUnit)
 | 
			
		||||
	}
 | 
			
		||||
	return name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseRequest takes a certificate request and generates a key and
 | 
			
		||||
// CSR from it. It does no validation -- caveat emptor. It will,
 | 
			
		||||
// however, fail if the key request is not valid (i.e., an unsupported
 | 
			
		||||
// curve or RSA key size). The lack of validation was specifically
 | 
			
		||||
// chosen to allow the end user to define a policy and validate the
 | 
			
		||||
// request appropriately before calling this function.
 | 
			
		||||
func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
 | 
			
		||||
	log.Info("received CSR")
 | 
			
		||||
	if req.KeyRequest == nil {
 | 
			
		||||
		req.KeyRequest = &KeyRequest{
 | 
			
		||||
			Algo: DefaultKeyRequest.Algo,
 | 
			
		||||
			Size: DefaultKeyRequest.Size,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Infof("generating key: %s-%d", req.KeyRequest.Algo, req.KeyRequest.Size)
 | 
			
		||||
	priv, err := req.KeyRequest.Generate()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch priv := priv.(type) {
 | 
			
		||||
	case *rsa.PrivateKey:
 | 
			
		||||
		key = x509.MarshalPKCS1PrivateKey(priv)
 | 
			
		||||
		block := pem.Block{
 | 
			
		||||
			Type:  "RSA PRIVATE KEY",
 | 
			
		||||
			Bytes: key,
 | 
			
		||||
		}
 | 
			
		||||
		key = pem.EncodeToMemory(&block)
 | 
			
		||||
	case *ecdsa.PrivateKey:
 | 
			
		||||
		key, err = x509.MarshalECPrivateKey(priv)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		block := pem.Block{
 | 
			
		||||
			Type:  "EC PRIVATE KEY",
 | 
			
		||||
			Bytes: key,
 | 
			
		||||
		}
 | 
			
		||||
		key = pem.EncodeToMemory(&block)
 | 
			
		||||
	default:
 | 
			
		||||
		panic("Generate should have failed to produce a valid key.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var tpl = x509.CertificateRequest{
 | 
			
		||||
		Subject:            req.Name(),
 | 
			
		||||
		SignatureAlgorithm: req.KeyRequest.SigAlgo(),
 | 
			
		||||
		DNSNames:           req.Hosts,
 | 
			
		||||
	}
 | 
			
		||||
	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Errorf("failed to generate a CSR: %v", err)
 | 
			
		||||
		// The use of CertificateError was a matter of some
 | 
			
		||||
		// debate; it is the one edge case in which a new
 | 
			
		||||
		// error category specifically for CSRs might be
 | 
			
		||||
		// useful, but it was deemed that one edge case did
 | 
			
		||||
		// not a new category justify.
 | 
			
		||||
		err = cferr.Wrap(cferr.CertificateError, cferr.BadRequest, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	block := pem.Block{
 | 
			
		||||
		Type:  "CERTIFICATE REQUEST",
 | 
			
		||||
		Bytes: csr,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Info("encoded CSR")
 | 
			
		||||
	csr = pem.EncodeToMemory(&block)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Generator is responsible for validating certificate requests.
 | 
			
		||||
type Generator struct {
 | 
			
		||||
	Validator func(*CertificateRequest) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ProcessRequest validates and processes the incoming request. It is
 | 
			
		||||
// a wrapper around a validator and the ParseRequest function.
 | 
			
		||||
func (g *Generator) ProcessRequest(req *CertificateRequest) (csr, key []byte, err error) {
 | 
			
		||||
 | 
			
		||||
	log.Info("generate received request")
 | 
			
		||||
	err = g.Validator(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("invalid request: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	csr, key, err = ParseRequest(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										373
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/csr/csr_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										373
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/csr/csr_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,373 @@
 | 
			
		|||
package csr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestKeyRequest ensures that key generation returns the same type of
 | 
			
		||||
// key specified in the KeyRequest.
 | 
			
		||||
func TestKeyRequest(t *testing.T) {
 | 
			
		||||
	var kr = &KeyRequest{"ecdsa", 256}
 | 
			
		||||
 | 
			
		||||
	priv, err := kr.Generate()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch priv.(type) {
 | 
			
		||||
	case *rsa.PrivateKey:
 | 
			
		||||
		if kr.Algo != "rsa" {
 | 
			
		||||
			t.Fatal("RSA key generated, but expected", kr.Algo)
 | 
			
		||||
		}
 | 
			
		||||
	case *ecdsa.PrivateKey:
 | 
			
		||||
		if kr.Algo != "ecdsa" {
 | 
			
		||||
			t.Fatal("ECDSA key generated, but expected", kr.Algo)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestPKIXName validates building a pkix.Name structure from a
 | 
			
		||||
// CertificateRequest.
 | 
			
		||||
func TestPKIXName(t *testing.T) {
 | 
			
		||||
	var kr = KeyRequest{"ecdsa", 256}
 | 
			
		||||
	var cr = &CertificateRequest{
 | 
			
		||||
		CN: "Test Common Name",
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare, Inc.",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				C:  "GB",
 | 
			
		||||
				ST: "London",
 | 
			
		||||
				L:  "London",
 | 
			
		||||
				O:  "CloudFlare, Inc",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
		KeyRequest: &kr,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name := cr.Name()
 | 
			
		||||
	if len(name.Country) != 2 {
 | 
			
		||||
		t.Fatal("Expected two countries in SubjInfo.")
 | 
			
		||||
	} else if len(name.Province) != 2 {
 | 
			
		||||
		t.Fatal("Expected two states in SubjInfo.")
 | 
			
		||||
	} else if len(name.Locality) != 2 {
 | 
			
		||||
		t.Fatal("Expected two localities in SubjInfo.")
 | 
			
		||||
	} else if len(name.Country) != 2 {
 | 
			
		||||
		t.Fatal("Expected two countries in SubjInfo.")
 | 
			
		||||
	} else if len(name.Organization) != 2 {
 | 
			
		||||
		t.Fatal("Expected two organization in SubjInfo.")
 | 
			
		||||
	} else if len(name.OrganizationalUnit) != 2 {
 | 
			
		||||
		t.Fatal("Expected two organizational units in SubjInfo.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestParseRequest ensures that a valid certificate request does not
 | 
			
		||||
// error.
 | 
			
		||||
func TestParseRequest(t *testing.T) {
 | 
			
		||||
	var kr = KeyRequest{"ecdsa", 256}
 | 
			
		||||
	var cr = &CertificateRequest{
 | 
			
		||||
		CN: "Test Common Name",
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare, Inc.",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				C:  "GB",
 | 
			
		||||
				ST: "London",
 | 
			
		||||
				L:  "London",
 | 
			
		||||
				O:  "CloudFlare, Inc",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Hosts:      []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
		KeyRequest: &kr,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, _, err := ParseRequest(cr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func whichCurve(sz int) elliptic.Curve {
 | 
			
		||||
	switch sz {
 | 
			
		||||
	case 256:
 | 
			
		||||
		return elliptic.P256()
 | 
			
		||||
	case 384:
 | 
			
		||||
		return elliptic.P384()
 | 
			
		||||
	case 521:
 | 
			
		||||
		return elliptic.P521()
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestECGeneration ensures that the proper curve is used depending on
 | 
			
		||||
// the bit size specified in a key request and that an appropriate
 | 
			
		||||
// signature algorithm is returned.
 | 
			
		||||
func TestECGeneration(t *testing.T) {
 | 
			
		||||
	var eckey *ecdsa.PrivateKey
 | 
			
		||||
 | 
			
		||||
	for _, sz := range []int{256, 384, 521} {
 | 
			
		||||
		kr := &KeyRequest{Algo: "ecdsa", Size: sz}
 | 
			
		||||
		priv, err := kr.Generate()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatalf("%v", err)
 | 
			
		||||
		}
 | 
			
		||||
		eckey = priv.(*ecdsa.PrivateKey)
 | 
			
		||||
		if eckey.Curve != whichCurve(sz) {
 | 
			
		||||
			t.Fatal("Generated key has wrong curve.")
 | 
			
		||||
		}
 | 
			
		||||
		if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm {
 | 
			
		||||
			t.Fatal("Invalid signature algorithm!")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRSAKeyGeneration(t *testing.T) {
 | 
			
		||||
	var rsakey *rsa.PrivateKey
 | 
			
		||||
 | 
			
		||||
	for _, sz := range []int{2048, 3072, 4096} {
 | 
			
		||||
		kr := &KeyRequest{Algo: "rsa", Size: sz}
 | 
			
		||||
		priv, err := kr.Generate()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatalf("%v", err)
 | 
			
		||||
		}
 | 
			
		||||
		rsakey = priv.(*rsa.PrivateKey)
 | 
			
		||||
		if rsakey.PublicKey.N.BitLen() != kr.Size {
 | 
			
		||||
			t.Fatal("Generated key has wrong size.")
 | 
			
		||||
		}
 | 
			
		||||
		if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm {
 | 
			
		||||
			t.Fatal("Invalid signature algorithm!")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestBadKeyRequest ensures that generating a key from a KeyRequest
 | 
			
		||||
// fails with an invalid algorithm, or an invalid RSA or ECDSA key
 | 
			
		||||
// size. An invalid ECDSA key size is any size other than 256, 384, or
 | 
			
		||||
// 521; an invalid RSA key size is any size less than 2048 bits.
 | 
			
		||||
func TestBadKeyRequest(t *testing.T) {
 | 
			
		||||
	kr := &KeyRequest{Algo: "yolocrypto", Size: 1024}
 | 
			
		||||
	if _, err := kr.Generate(); err == nil {
 | 
			
		||||
		t.Fatal("Key generation should fail with invalid algorithm")
 | 
			
		||||
	} else if sa := kr.SigAlgo(); sa != x509.UnknownSignatureAlgorithm {
 | 
			
		||||
		t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kr.Algo = "ecdsa"
 | 
			
		||||
	if _, err := kr.Generate(); err == nil {
 | 
			
		||||
		t.Fatal("Key generation should fail with invalid key size")
 | 
			
		||||
	} else if sa := kr.SigAlgo(); sa != x509.ECDSAWithSHA1 {
 | 
			
		||||
		t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kr.Algo = "rsa"
 | 
			
		||||
	if _, err := kr.Generate(); err == nil {
 | 
			
		||||
		t.Fatal("Key generation should fail with invalid key size")
 | 
			
		||||
	} else if sa := kr.SigAlgo(); sa != x509.SHA1WithRSA {
 | 
			
		||||
		t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestDefaultKeyRequest makes sure that certificate requests without
 | 
			
		||||
// explicit key requests fall back to the default key request.
 | 
			
		||||
func TestDefaultKeyRequest(t *testing.T) {
 | 
			
		||||
	var req = &CertificateRequest{
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		CN:    "cloudflare.com",
 | 
			
		||||
		Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
	}
 | 
			
		||||
	_, priv, err := ParseRequest(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the default key type changes, this will need to be changed.
 | 
			
		||||
	block, _ := pem.Decode(priv)
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		t.Fatal("Bad private key was generated!")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch block.Type {
 | 
			
		||||
	case "RSA PRIVATE KEY":
 | 
			
		||||
		if DefaultKeyRequest.Algo != "rsa" {
 | 
			
		||||
			t.Fatal("Invalid default key request.")
 | 
			
		||||
		}
 | 
			
		||||
	case "EC PRIVATE KEY":
 | 
			
		||||
		if DefaultKeyRequest.Algo != "ecdsa" {
 | 
			
		||||
			t.Fatal("Invalid default key request.")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestRSACertRequest validates parsing a certificate request with an
 | 
			
		||||
// RSA key.
 | 
			
		||||
func TestRSACertRequest(t *testing.T) {
 | 
			
		||||
	var req = &CertificateRequest{
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		CN:    "cloudflare.com",
 | 
			
		||||
		Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
		KeyRequest: &KeyRequest{
 | 
			
		||||
			Algo: "rsa",
 | 
			
		||||
			Size: 2048,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	_, _, err := ParseRequest(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestBadCertRequest checks for failure conditions of ParseRequest.
 | 
			
		||||
func TestBadCertRequest(t *testing.T) {
 | 
			
		||||
	var req = &CertificateRequest{
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		CN:    "cloudflare.com",
 | 
			
		||||
		Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
		KeyRequest: &KeyRequest{
 | 
			
		||||
			Algo: "yolo-crypto",
 | 
			
		||||
			Size: 2048,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	_, _, err := ParseRequest(req)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("ParseRequest should fail with a bad key algorithm.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// testValidator is a stripped-down validator that checks to make sure
 | 
			
		||||
// the request has a common name. It should mimic some of the
 | 
			
		||||
// functionality expected in an actual validator.
 | 
			
		||||
func testValidator(req *CertificateRequest) error {
 | 
			
		||||
	if req.CN == "" {
 | 
			
		||||
		return errors.NewBadRequestMissingParameter("CN")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestGenerator ensures that a valid request is processed properly
 | 
			
		||||
// and returns a certificate request and key.
 | 
			
		||||
func TestGenerator(t *testing.T) {
 | 
			
		||||
	g := &Generator{testValidator}
 | 
			
		||||
	var req = &CertificateRequest{
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		CN:    "cloudflare.com",
 | 
			
		||||
		Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
		KeyRequest: &KeyRequest{
 | 
			
		||||
			Algo: "rsa",
 | 
			
		||||
			Size: 2048,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, _, err := g.ProcessRequest(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestBadGenerator ensures that a request that fails the validator is
 | 
			
		||||
// not processed.
 | 
			
		||||
func TestBadGenerator(t *testing.T) {
 | 
			
		||||
	g := &Generator{testValidator}
 | 
			
		||||
	missingCN := &CertificateRequest{
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		// Missing CN
 | 
			
		||||
		Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
		KeyRequest: &KeyRequest{
 | 
			
		||||
			Algo: "rsa",
 | 
			
		||||
			Size: 2048,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, _, err := g.ProcessRequest(missingCN)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatalf("Request should have failed.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWeakCSR(t *testing.T) {
 | 
			
		||||
	weakKey := &CertificateRequest{
 | 
			
		||||
		Names: []Name{
 | 
			
		||||
			{
 | 
			
		||||
				C:  "US",
 | 
			
		||||
				ST: "California",
 | 
			
		||||
				L:  "San Francisco",
 | 
			
		||||
				O:  "CloudFlare",
 | 
			
		||||
				OU: "Systems Engineering",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		CN:    "cloudflare.com",
 | 
			
		||||
		Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
 | 
			
		||||
		KeyRequest: &KeyRequest{
 | 
			
		||||
			Algo: "rsa",
 | 
			
		||||
			Size: 1024,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	g := &Generator{testValidator}
 | 
			
		||||
 | 
			
		||||
	_, _, err := g.ProcessRequest(weakKey)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatalf("Request should have failed.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/*
 | 
			
		||||
Package errors provides error types returned in CF SSL.
 | 
			
		||||
 | 
			
		||||
1. Type Error is intended for errors produced by CF SSL packages.
 | 
			
		||||
It formats to a json object that consists of an error message and a 4-digit code for error reasoning.
 | 
			
		||||
 | 
			
		||||
Example: {"code":1002, "message": "Failed to decode certificate"}
 | 
			
		||||
 | 
			
		||||
The index of codes are listed below:
 | 
			
		||||
	1XXX: CertificateError
 | 
			
		||||
	    1000: Unknown
 | 
			
		||||
	    1001: ReadFailed
 | 
			
		||||
	    1002: DecodeFailed
 | 
			
		||||
	    1003: ParseFailed
 | 
			
		||||
	    1100: SelfSigned
 | 
			
		||||
	    12XX: VerifyFailed
 | 
			
		||||
	        121X: CertificateInvalid
 | 
			
		||||
	            1210: NotAuthorizedToSign
 | 
			
		||||
	            1211: Expired
 | 
			
		||||
	            1212: CANotAuthorizedForThisName
 | 
			
		||||
	            1213: TooManyIntermediates
 | 
			
		||||
	            1214: IncompatibleUsage
 | 
			
		||||
	        1220: UnknownAuthority
 | 
			
		||||
	2XXX: PrivatekeyError
 | 
			
		||||
	    2000: Unknown
 | 
			
		||||
	    2001: ReadFailed
 | 
			
		||||
	    2002: DecodeFailed
 | 
			
		||||
	    2003: ParseFailed
 | 
			
		||||
	    2100: Encrypted
 | 
			
		||||
	    2200: NotRSA
 | 
			
		||||
	    2300: KeyMismatch
 | 
			
		||||
	    2400: GenerationFailed
 | 
			
		||||
	    2500: Unavailable
 | 
			
		||||
	3XXX: IntermediatesError
 | 
			
		||||
	4XXX: RootError
 | 
			
		||||
	5XXX: PolicyError
 | 
			
		||||
	    5100: NoKeyUsages
 | 
			
		||||
	    5200: InvalidPolicy
 | 
			
		||||
	    5300: InvalidRequest
 | 
			
		||||
	    6XXX: DialError
 | 
			
		||||
 | 
			
		||||
2. Type HttpError is intended for CF SSL API to consume. It contains a HTTP status code that will be read and returned
 | 
			
		||||
by the API server.
 | 
			
		||||
*/
 | 
			
		||||
package errors
 | 
			
		||||
							
								
								
									
										351
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/errors/error.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										351
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/errors/error.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,351 @@
 | 
			
		|||
package errors
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Error is the error type usually returned by functions in CF SSL package.
 | 
			
		||||
// It contains a 4-digit error code where the most significant digit
 | 
			
		||||
// describes the category where the error occurred and the rest 3 digits
 | 
			
		||||
// describe the specific error reason.
 | 
			
		||||
type Error struct {
 | 
			
		||||
	ErrorCode int    `json:"code"`
 | 
			
		||||
	Message   string `json:"message"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Category is the most significant digit of the error code.
 | 
			
		||||
type Category int
 | 
			
		||||
 | 
			
		||||
// Reason is the last 3 digits of the error code.
 | 
			
		||||
type Reason int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Success indicates no error occurred.
 | 
			
		||||
	Success Category = 1000 * iota // 0XXX
 | 
			
		||||
 | 
			
		||||
	// CertificateError indicates a fault in a certificate.
 | 
			
		||||
	CertificateError // 1XXX
 | 
			
		||||
 | 
			
		||||
	// PrivateKeyError indicates a fault in a private key.
 | 
			
		||||
	PrivateKeyError // 2XXX
 | 
			
		||||
 | 
			
		||||
	// IntermediatesError indicates a fault in an intermediate.
 | 
			
		||||
	IntermediatesError // 3XXX
 | 
			
		||||
 | 
			
		||||
	// RootError indicates a fault in a root.
 | 
			
		||||
	RootError // 4XXX
 | 
			
		||||
 | 
			
		||||
	// PolicyError indicates an error arising from a malformed or
 | 
			
		||||
	// non-existent policy, or a breach of policy.
 | 
			
		||||
	PolicyError // 5XXX
 | 
			
		||||
 | 
			
		||||
	// DialError indicates a network fault.
 | 
			
		||||
	DialError // 6XXX
 | 
			
		||||
 | 
			
		||||
	// APIClientError indicates a problem with the API client.
 | 
			
		||||
	APIClientError // 7XXX
 | 
			
		||||
 | 
			
		||||
	// OCSPError indicates a problem with OCSP signing
 | 
			
		||||
	OCSPError // 8XXX
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// None is a non-specified error.
 | 
			
		||||
const (
 | 
			
		||||
	None Reason = iota
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Warning code for a success
 | 
			
		||||
const (
 | 
			
		||||
	BundleExpiringBit      int = 1 << iota // 0x01
 | 
			
		||||
	BundleNotUbiquitousBit                 // 0x02
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Parsing errors
 | 
			
		||||
const (
 | 
			
		||||
	Unknown      Reason = iota // X000
 | 
			
		||||
	ReadFailed                 // X001
 | 
			
		||||
	DecodeFailed               // X002
 | 
			
		||||
	ParseFailed                // X003
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The following represent certificate non-parsing errors, and must be
 | 
			
		||||
// specified along with CertificateError.
 | 
			
		||||
const (
 | 
			
		||||
	// SelfSigned indicates that a certificate is self-signed and
 | 
			
		||||
	// cannot be used in the manner being attempted.
 | 
			
		||||
	SelfSigned Reason = 100 * (iota + 1) // Code 11XX
 | 
			
		||||
 | 
			
		||||
	// VerifyFailed is an X.509 verification failure. The least two
 | 
			
		||||
	// significant digits of 12XX is determined as the actual x509
 | 
			
		||||
	// error is examined.
 | 
			
		||||
	VerifyFailed // Code 12XX
 | 
			
		||||
 | 
			
		||||
	// BadRequest indicates that the certificate request is invalid.
 | 
			
		||||
	BadRequest // Code 13XX
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	certificateInvalid = 10 * (iota + 1) //121X
 | 
			
		||||
	unknownAuthority                     //122x
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The following represent private-key non-parsing errors, and must be
 | 
			
		||||
// specified with PrivateKeyError.
 | 
			
		||||
const (
 | 
			
		||||
	// Encrypted indicates that the private key is a PKCS #8 encrypted
 | 
			
		||||
	// private key. At this time, CFSSL does not support decrypting
 | 
			
		||||
	// these keys.
 | 
			
		||||
	Encrypted Reason = 100 * (iota + 1) //21XX
 | 
			
		||||
 | 
			
		||||
	// NotRSAOrECC indicates that they key is not an RSA or ECC
 | 
			
		||||
	// private key; these are the only two private key types supported
 | 
			
		||||
	// at this time by CFSSL.
 | 
			
		||||
	NotRSAOrECC //22XX
 | 
			
		||||
 | 
			
		||||
	// KeyMismatch indicates that the private key does not match
 | 
			
		||||
	// the public key or certificate being presented with the key.
 | 
			
		||||
	KeyMismatch //23XX
 | 
			
		||||
 | 
			
		||||
	// GenerationFailed indicates that a private key could not
 | 
			
		||||
	// be generated.
 | 
			
		||||
	GenerationFailed //24XX
 | 
			
		||||
 | 
			
		||||
	// Unavailable indicates that a private key mechanism (such as
 | 
			
		||||
	// PKCS #11) was requested but support for that mechanism is
 | 
			
		||||
	// not available.
 | 
			
		||||
	Unavailable
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The following are policy-related non-parsing errors, and must be
 | 
			
		||||
// specified along with PolicyError.
 | 
			
		||||
const (
 | 
			
		||||
	// NoKeyUsages indicates that the profile does not permit any
 | 
			
		||||
	// key usages for the certificate.
 | 
			
		||||
	NoKeyUsages Reason = 100 * (iota + 1) // 51XX
 | 
			
		||||
 | 
			
		||||
	// InvalidPolicy indicates that policy being requested is not
 | 
			
		||||
	// a valid policy or does not exist.
 | 
			
		||||
	InvalidPolicy // 52XX
 | 
			
		||||
 | 
			
		||||
	// InvalidRequest indicates a certificate request violated the
 | 
			
		||||
	// constraints of the policy being applied to the request.
 | 
			
		||||
	InvalidRequest // 53XX
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The following are API client related errors, and should be
 | 
			
		||||
// specified with APIClientError.
 | 
			
		||||
const (
 | 
			
		||||
	// AuthenticationFailure occurs when the client is unable
 | 
			
		||||
	// to obtain an authentication token for the request.
 | 
			
		||||
	AuthenticationFailure Reason = 100 * (iota + 1)
 | 
			
		||||
 | 
			
		||||
	// JSONError wraps an encoding/json error.
 | 
			
		||||
	JSONError
 | 
			
		||||
 | 
			
		||||
	// IOError wraps an io/ioutil error.
 | 
			
		||||
	IOError
 | 
			
		||||
 | 
			
		||||
	// ClientHTTPError wraps a net/http error.
 | 
			
		||||
	ClientHTTPError
 | 
			
		||||
 | 
			
		||||
	// ServerRequestFailed covers any other failures from the API
 | 
			
		||||
	// client.
 | 
			
		||||
	ServerRequestFailed
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The following are OCSP related errors, and should be
 | 
			
		||||
// specified with OCSPError
 | 
			
		||||
const (
 | 
			
		||||
	// IssuerMismatch ocurs when the certificate in the OCSP signing
 | 
			
		||||
	// request was not issued by the CA that this responder responds for.
 | 
			
		||||
	IssuerMismatch Reason = 100 * (iota + 1) // 81XX
 | 
			
		||||
 | 
			
		||||
	// InvalidStatus occurs when the OCSP signing requests includes an
 | 
			
		||||
	// invalid value for the certificate status.
 | 
			
		||||
	InvalidStatus
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The error interface implementation, which formats to a JSON object string.
 | 
			
		||||
func (e *Error) Error() string {
 | 
			
		||||
	marshaled, err := json.Marshal(e)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	return string(marshaled)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns an error that contains  an error code and message derived from
 | 
			
		||||
// the given category, reason. Currently, to avoid confusion, it is not
 | 
			
		||||
// allowed to create an error of category Success
 | 
			
		||||
func New(category Category, reason Reason) *Error {
 | 
			
		||||
	errorCode := int(category) + int(reason)
 | 
			
		||||
	var msg string
 | 
			
		||||
	switch category {
 | 
			
		||||
	case OCSPError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case ReadFailed:
 | 
			
		||||
			msg = "No certificate provided"
 | 
			
		||||
		case IssuerMismatch:
 | 
			
		||||
			msg = "Certificate not issued by this issuer"
 | 
			
		||||
		case InvalidStatus:
 | 
			
		||||
			msg = "Invalid revocation status"
 | 
			
		||||
		}
 | 
			
		||||
	case CertificateError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case Unknown:
 | 
			
		||||
			msg = "Unknown certificate error"
 | 
			
		||||
		case ReadFailed:
 | 
			
		||||
			msg = "Failed to read certificate"
 | 
			
		||||
		case DecodeFailed:
 | 
			
		||||
			msg = "Failed to decode certificate"
 | 
			
		||||
		case ParseFailed:
 | 
			
		||||
			msg = "Failed to parse certificate"
 | 
			
		||||
		case SelfSigned:
 | 
			
		||||
			msg = "Certificate is self signed"
 | 
			
		||||
		case VerifyFailed:
 | 
			
		||||
			msg = "Unable to verify certificate"
 | 
			
		||||
		case BadRequest:
 | 
			
		||||
			msg = "Invalid certificate request"
 | 
			
		||||
		default:
 | 
			
		||||
			panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CertificateError.",
 | 
			
		||||
				reason))
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	case PrivateKeyError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case Unknown:
 | 
			
		||||
			msg = "Unknown private key error"
 | 
			
		||||
		case ReadFailed:
 | 
			
		||||
			msg = "Failed to read private key"
 | 
			
		||||
		case DecodeFailed:
 | 
			
		||||
			msg = "Failed to decode private key"
 | 
			
		||||
		case ParseFailed:
 | 
			
		||||
			msg = "Failed to parse private key"
 | 
			
		||||
		case Encrypted:
 | 
			
		||||
			msg = "Private key is encrypted."
 | 
			
		||||
		case NotRSAOrECC:
 | 
			
		||||
			msg = "Private key algorithm is not RSA or ECC"
 | 
			
		||||
		case KeyMismatch:
 | 
			
		||||
			msg = "Private key does not match public key"
 | 
			
		||||
		case GenerationFailed:
 | 
			
		||||
			msg = "Failed to new private key"
 | 
			
		||||
		case Unavailable:
 | 
			
		||||
			msg = "Private key is unavailable"
 | 
			
		||||
		default:
 | 
			
		||||
			panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category PrivateKeyError.",
 | 
			
		||||
				reason))
 | 
			
		||||
		}
 | 
			
		||||
	case IntermediatesError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case Unknown:
 | 
			
		||||
			msg = "Unknown intermediate certificate error"
 | 
			
		||||
		case ReadFailed:
 | 
			
		||||
			msg = "Failed to read intermediate certificate"
 | 
			
		||||
		case DecodeFailed:
 | 
			
		||||
			msg = "Failed to decode intermediate certificate"
 | 
			
		||||
		case ParseFailed:
 | 
			
		||||
			msg = "Failed to parse intermediate certificate"
 | 
			
		||||
		default:
 | 
			
		||||
			panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category IntermediatesError.",
 | 
			
		||||
				reason))
 | 
			
		||||
		}
 | 
			
		||||
	case RootError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case Unknown:
 | 
			
		||||
			msg = "Unknown root certificate error"
 | 
			
		||||
		case ReadFailed:
 | 
			
		||||
			msg = "Failed to read root certificate"
 | 
			
		||||
		case DecodeFailed:
 | 
			
		||||
			msg = "Failed to decode root certificate"
 | 
			
		||||
		case ParseFailed:
 | 
			
		||||
			msg = "Failed to parse root certificate"
 | 
			
		||||
		default:
 | 
			
		||||
			panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category RootError.",
 | 
			
		||||
				reason))
 | 
			
		||||
		}
 | 
			
		||||
	case PolicyError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case Unknown:
 | 
			
		||||
			msg = "Unknown policy error"
 | 
			
		||||
		case NoKeyUsages:
 | 
			
		||||
			msg = "Invalid policy: no key usage available"
 | 
			
		||||
		case InvalidPolicy:
 | 
			
		||||
			msg = "Invalid or unknown policy"
 | 
			
		||||
		case InvalidRequest:
 | 
			
		||||
			msg = "Policy violation request"
 | 
			
		||||
		default:
 | 
			
		||||
			panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category PolicyError.",
 | 
			
		||||
				reason))
 | 
			
		||||
		}
 | 
			
		||||
	case DialError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case Unknown:
 | 
			
		||||
			msg = "Failed to dial remote server"
 | 
			
		||||
		default:
 | 
			
		||||
			panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category DialError.",
 | 
			
		||||
				reason))
 | 
			
		||||
		}
 | 
			
		||||
	case APIClientError:
 | 
			
		||||
		switch reason {
 | 
			
		||||
		case AuthenticationFailure:
 | 
			
		||||
			msg = "API client authentication failure"
 | 
			
		||||
		case JSONError:
 | 
			
		||||
			msg = "API client JSON config error"
 | 
			
		||||
		case ClientHTTPError:
 | 
			
		||||
			msg = "API client HTTP error"
 | 
			
		||||
		case IOError:
 | 
			
		||||
			msg = "API client IO error"
 | 
			
		||||
		case ServerRequestFailed:
 | 
			
		||||
			msg = "API client error: Server request failed"
 | 
			
		||||
		default:
 | 
			
		||||
			panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category APIClientError.",
 | 
			
		||||
				reason))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		panic(fmt.Sprintf("Unsupported CF-SSL error type: %d.",
 | 
			
		||||
			category))
 | 
			
		||||
	}
 | 
			
		||||
	return &Error{ErrorCode: errorCode, Message: msg}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wrap returns an error that contains the given error and an error code derived from
 | 
			
		||||
// the given category, reason and the error. Currently, to avoid confusion, it is not
 | 
			
		||||
// allowed to create an error of category Success
 | 
			
		||||
func Wrap(category Category, reason Reason, err error) *Error {
 | 
			
		||||
	errorCode := int(category) + int(reason)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		panic("Wrap needs a supplied error to initialize.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// do not double wrap a error
 | 
			
		||||
	switch err.(type) {
 | 
			
		||||
	case *Error:
 | 
			
		||||
		panic("Unable to wrap a wrapped error.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch category {
 | 
			
		||||
	case CertificateError:
 | 
			
		||||
		// given VerifyFailed , report the status with more detailed status code
 | 
			
		||||
		// for some certificate errors we care.
 | 
			
		||||
		if reason == VerifyFailed {
 | 
			
		||||
			switch errorType := err.(type) {
 | 
			
		||||
			case x509.CertificateInvalidError:
 | 
			
		||||
				errorCode += certificateInvalid + int(errorType.Reason)
 | 
			
		||||
			case x509.UnknownAuthorityError:
 | 
			
		||||
				errorCode += unknownAuthority
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case PrivateKeyError, IntermediatesError, RootError, PolicyError, DialError, APIClientError:
 | 
			
		||||
		// no-op, just use the error
 | 
			
		||||
	default:
 | 
			
		||||
		panic(fmt.Sprintf("Unsupported CF-SSL error type: %d.",
 | 
			
		||||
			category))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Error{ErrorCode: errorCode, Message: err.Error()}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										69
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/errors/error_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										69
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/errors/error_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
package errors
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	err := New(CertificateError, Unknown)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Error creation failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if err.ErrorCode != int(CertificateError)+int(Unknown) {
 | 
			
		||||
		t.Fatal("Error code construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if err.Message != "Unknown certificate error" {
 | 
			
		||||
		t.Fatal("Error message construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWrap(t *testing.T) {
 | 
			
		||||
	msg := "Arbitrary error message"
 | 
			
		||||
	err := Wrap(CertificateError, Unknown, errors.New(msg))
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Error creation failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if err.ErrorCode != int(CertificateError)+int(Unknown) {
 | 
			
		||||
		t.Fatal("Error code construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if err.Message != msg {
 | 
			
		||||
		t.Fatal("Error message construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = Wrap(CertificateError, VerifyFailed, x509.CertificateInvalidError{Reason: x509.Expired})
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Error creation failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if err.ErrorCode != int(CertificateError)+int(VerifyFailed)+certificateInvalid+int(x509.Expired) {
 | 
			
		||||
		t.Fatal("Error code construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if err.Message != "x509: certificate has expired or is not yet valid" {
 | 
			
		||||
		t.Fatal("Error message construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMarshal(t *testing.T) {
 | 
			
		||||
	msg := "Arbitrary error message"
 | 
			
		||||
	err := Wrap(CertificateError, Unknown, errors.New(msg))
 | 
			
		||||
	bytes, _ := json.Marshal(err)
 | 
			
		||||
	var received Error
 | 
			
		||||
	json.Unmarshal(bytes, &received)
 | 
			
		||||
	if received.ErrorCode != int(CertificateError)+int(Unknown) {
 | 
			
		||||
		t.Fatal("Error code construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if received.Message != msg {
 | 
			
		||||
		t.Fatal("Error message construction failed.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestErrorString(t *testing.T) {
 | 
			
		||||
	msg := "Arbitrary error message"
 | 
			
		||||
	err := Wrap(CertificateError, Unknown, errors.New(msg))
 | 
			
		||||
	str := err.Error()
 | 
			
		||||
	if str != `{"code":1000,"message":"`+msg+`"}` {
 | 
			
		||||
		t.Fatal("Incorrect Error():", str)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
package errors
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HTTPError is an augmented error with a HTTP status code.
 | 
			
		||||
type HTTPError struct {
 | 
			
		||||
	StatusCode int
 | 
			
		||||
	error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error implements the error interface.
 | 
			
		||||
func (e *HTTPError) Error() string {
 | 
			
		||||
	return e.error.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewMethodNotAllowed returns an appropriate error in the case that
 | 
			
		||||
// an HTTP client uses an invalid method (i.e. a GET in place of a POST)
 | 
			
		||||
// on an API endpoint.
 | 
			
		||||
func NewMethodNotAllowed(method string) *HTTPError {
 | 
			
		||||
	return &HTTPError{http.StatusMethodNotAllowed, errors.New(`Method is not allowed:"` + method + `"`)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBadRequest creates a HttpError with the given error and error code 400.
 | 
			
		||||
func NewBadRequest(err error) *HTTPError {
 | 
			
		||||
	return &HTTPError{http.StatusBadRequest, err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBadRequestString returns a HttpError with the supplied message
 | 
			
		||||
// and error code 400.
 | 
			
		||||
func NewBadRequestString(s string) *HTTPError {
 | 
			
		||||
	return NewBadRequest(errors.New(s))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBadRequestMissingParameter returns a 400 HttpError as a required
 | 
			
		||||
// parameter is missing in the HTTP request.
 | 
			
		||||
func NewBadRequestMissingParameter(s string) *HTTPError {
 | 
			
		||||
	return NewBadRequestString(`Missing parameter "` + s + `"`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBadRequestUnwantedParameter returns a 400 HttpError as a unnecessary
 | 
			
		||||
// parameter is present in the HTTP request.
 | 
			
		||||
func NewBadRequestUnwantedParameter(s string) *HTTPError {
 | 
			
		||||
	return NewBadRequestString(`Unwanted parameter "` + s + `"`)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										227
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/helpers.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										227
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/helpers.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,227 @@
 | 
			
		|||
// Package helpers implements utility functionality common to many
 | 
			
		||||
// CF-SSL packages.
 | 
			
		||||
package helpers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// OneYear is a time.Duration representing a year's worth of seconds.
 | 
			
		||||
const OneYear = 8760 * time.Hour
 | 
			
		||||
 | 
			
		||||
// OneDay is a time.Duration representing a day's worth of seconds.
 | 
			
		||||
const OneDay = 24 * time.Hour
 | 
			
		||||
 | 
			
		||||
// KeyLength returns the bit size of ECDSA or RSA PublicKey
 | 
			
		||||
func KeyLength(key interface{}) int {
 | 
			
		||||
	if key == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	if ecdsaKey, ok := key.(*ecdsa.PublicKey); ok {
 | 
			
		||||
		return ecdsaKey.Curve.Params().BitSize
 | 
			
		||||
	} else if rsaKey, ok := key.(*rsa.PublicKey); ok {
 | 
			
		||||
		return rsaKey.N.BitLen()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExpiryTime returns the time when the certificate chain is expired.
 | 
			
		||||
func ExpiryTime(chain []*x509.Certificate) *time.Time {
 | 
			
		||||
	if len(chain) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	notAfter := chain[0].NotAfter
 | 
			
		||||
	for _, cert := range chain {
 | 
			
		||||
		if cert.NotAfter.Before(notAfter) {
 | 
			
		||||
			notAfter = cert.NotAfter
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ¬After
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SignatureString returns the TLS signature string corresponding to
 | 
			
		||||
// an X509 signature algorithm.
 | 
			
		||||
func SignatureString(alg x509.SignatureAlgorithm) string {
 | 
			
		||||
	switch alg {
 | 
			
		||||
	case x509.MD2WithRSA:
 | 
			
		||||
		return "MD2WithRSA"
 | 
			
		||||
	case x509.MD5WithRSA:
 | 
			
		||||
		return "MD5WithRSA"
 | 
			
		||||
	case x509.SHA1WithRSA:
 | 
			
		||||
		return "SHA1WithRSA"
 | 
			
		||||
	case x509.SHA256WithRSA:
 | 
			
		||||
		return "SHA256WithRSA"
 | 
			
		||||
	case x509.SHA384WithRSA:
 | 
			
		||||
		return "SHA384WithRSA"
 | 
			
		||||
	case x509.SHA512WithRSA:
 | 
			
		||||
		return "SHA512WithRSA"
 | 
			
		||||
	case x509.DSAWithSHA1:
 | 
			
		||||
		return "DSAWithSHA1"
 | 
			
		||||
	case x509.DSAWithSHA256:
 | 
			
		||||
		return "DSAWithSHA256"
 | 
			
		||||
	case x509.ECDSAWithSHA1:
 | 
			
		||||
		return "ECDSAWithSHA1"
 | 
			
		||||
	case x509.ECDSAWithSHA256:
 | 
			
		||||
		return "ECDSAWithSHA256"
 | 
			
		||||
	case x509.ECDSAWithSHA384:
 | 
			
		||||
		return "ECDSAWithSHA384"
 | 
			
		||||
	case x509.ECDSAWithSHA512:
 | 
			
		||||
		return "ECDSAWithSHA512"
 | 
			
		||||
	default:
 | 
			
		||||
		return "Unknown Signature"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HashAlgoString returns the hash algorithm name contains in the signature
 | 
			
		||||
// method.
 | 
			
		||||
func HashAlgoString(alg x509.SignatureAlgorithm) string {
 | 
			
		||||
	switch alg {
 | 
			
		||||
	case x509.MD2WithRSA:
 | 
			
		||||
		return "MD2"
 | 
			
		||||
	case x509.MD5WithRSA:
 | 
			
		||||
		return "MD5"
 | 
			
		||||
	case x509.SHA1WithRSA:
 | 
			
		||||
		return "SHA1"
 | 
			
		||||
	case x509.SHA256WithRSA:
 | 
			
		||||
		return "SHA256"
 | 
			
		||||
	case x509.SHA384WithRSA:
 | 
			
		||||
		return "SHA384"
 | 
			
		||||
	case x509.SHA512WithRSA:
 | 
			
		||||
		return "SHA512"
 | 
			
		||||
	case x509.DSAWithSHA1:
 | 
			
		||||
		return "SHA1"
 | 
			
		||||
	case x509.DSAWithSHA256:
 | 
			
		||||
		return "SHA256"
 | 
			
		||||
	case x509.ECDSAWithSHA1:
 | 
			
		||||
		return "SHA1"
 | 
			
		||||
	case x509.ECDSAWithSHA256:
 | 
			
		||||
		return "SHA256"
 | 
			
		||||
	case x509.ECDSAWithSHA384:
 | 
			
		||||
		return "SHA384"
 | 
			
		||||
	case x509.ECDSAWithSHA512:
 | 
			
		||||
		return "SHA512"
 | 
			
		||||
	default:
 | 
			
		||||
		return "Unknown Hash Algorithm"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCertificatesPEM parses a sequence of PEM-encoded certificate and returns them.
 | 
			
		||||
func ParseCertificatesPEM(certsPEM []byte) ([]*x509.Certificate, error) {
 | 
			
		||||
	var certs []*x509.Certificate
 | 
			
		||||
	var err error
 | 
			
		||||
	certsPEM = bytes.TrimSpace(certsPEM)
 | 
			
		||||
	for len(certsPEM) > 0 {
 | 
			
		||||
		var cert *x509.Certificate
 | 
			
		||||
		cert, certsPEM, err = ParseOneCertificateFromPEM(certsPEM)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
 | 
			
		||||
		} else if cert == nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		certs = append(certs, cert)
 | 
			
		||||
	}
 | 
			
		||||
	if len(certsPEM) > 0 {
 | 
			
		||||
		return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
 | 
			
		||||
	}
 | 
			
		||||
	return certs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseSelfSignedCertificatePEM parses a PEM-encoded certificate and check if it is self-signed.
 | 
			
		||||
func ParseSelfSignedCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
 | 
			
		||||
	cert, err := ParseCertificatePEM(certPEM)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.CertificateError, cferr.VerifyFailed, err)
 | 
			
		||||
	}
 | 
			
		||||
	return cert, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCertificatePEM parses and returns a PEM-encoded certificate.
 | 
			
		||||
func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
 | 
			
		||||
	certPEM = bytes.TrimSpace(certPEM)
 | 
			
		||||
	cert, rest, err := ParseOneCertificateFromPEM(certPEM)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Log the actual parsing error but throw a default parse error message.
 | 
			
		||||
		log.Debugf("Certificate parsing error: %v", err)
 | 
			
		||||
		return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
 | 
			
		||||
	} else if cert == nil {
 | 
			
		||||
		return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
 | 
			
		||||
	} else if len(rest) > 0 {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("The PEM file should contain only one certificate."))
 | 
			
		||||
	}
 | 
			
		||||
	return cert, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseOneCertificateFromPEM attempts to parse one certificate from the top of the certsPEM,
 | 
			
		||||
// which may contain multiple certs.
 | 
			
		||||
func ParseOneCertificateFromPEM(certsPEM []byte) (cert *x509.Certificate, rest []byte, err error) {
 | 
			
		||||
	block, rest := pem.Decode(certsPEM)
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		return nil, rest, nil
 | 
			
		||||
	}
 | 
			
		||||
	cert, err = x509.ParseCertificate(block.Bytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, rest, err
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParsePrivateKeyPEM parses and returns a PEM-encoded private
 | 
			
		||||
// key. The private key may be either an unencrypted PKCS#8, PKCS#1,
 | 
			
		||||
// or elliptic private key.
 | 
			
		||||
func ParsePrivateKeyPEM(keyPEM []byte) (key crypto.Signer, err error) {
 | 
			
		||||
	keyDER, _ := pem.Decode(keyPEM)
 | 
			
		||||
	if keyDER == nil {
 | 
			
		||||
		return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
 | 
			
		||||
	}
 | 
			
		||||
	if procType, ok := keyDER.Headers["Proc-Type"]; ok {
 | 
			
		||||
		if strings.Contains(procType, "ENCRYPTED") {
 | 
			
		||||
			return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ParsePrivateKeyDER(keyDER.Bytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, or elliptic curve
 | 
			
		||||
// DER-encoded private key. The key must not be in PEM format.
 | 
			
		||||
func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
 | 
			
		||||
	generalKey, err := x509.ParsePKCS8PrivateKey(keyDER)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		generalKey, err = x509.ParsePKCS1PrivateKey(keyDER)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			generalKey, err = x509.ParseECPrivateKey(keyDER)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				// We don't include the actual error into
 | 
			
		||||
				// the final error. The reason might be
 | 
			
		||||
				// we don't want to leak any info about
 | 
			
		||||
				// the private key.
 | 
			
		||||
				return nil, cferr.New(cferr.PrivateKeyError,
 | 
			
		||||
					cferr.ParseFailed)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch generalKey.(type) {
 | 
			
		||||
	case *rsa.PrivateKey:
 | 
			
		||||
		return generalKey.(*rsa.PrivateKey), nil
 | 
			
		||||
	case *ecdsa.PrivateKey:
 | 
			
		||||
		return generalKey.(*ecdsa.PrivateKey), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										273
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/helpers_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										273
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/helpers_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,273 @@
 | 
			
		|||
package helpers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testCertFile            = "testdata/cert.pem"
 | 
			
		||||
	testBundleFile          = "testdata/bundle.pem"
 | 
			
		||||
	testExtraWSCertFile     = "testdata/cert_with_whitespace.pem"
 | 
			
		||||
	testExtraWSBundleFile   = "testdata/bundle_with_whitespace.pem"
 | 
			
		||||
	testMessedUpBundleFile  = "testdata/messed_up_bundle.pem"
 | 
			
		||||
	testMessedUpCertFile    = "testdata/messedupcert.pem"
 | 
			
		||||
	testEmptyCertFile       = "testdata/emptycert.pem"
 | 
			
		||||
	testPrivateKey          = "testdata/priv_key.pem"
 | 
			
		||||
	testMessedUpPrivateKey  = "testdata/messed_up_priv_key.pem"
 | 
			
		||||
	testEncryptedPrivateKey = "testdata/enc_priv_key.pem"
 | 
			
		||||
	testEmptyPem            = "testdata/empty.pem"
 | 
			
		||||
	testNoHeaderCert        = "testdata/noheadercert.pem"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestKeyLength(t *testing.T) {
 | 
			
		||||
	expNil := 0
 | 
			
		||||
	recNil := KeyLength(nil)
 | 
			
		||||
	if expNil != recNil {
 | 
			
		||||
		t.Fatal("KeyLength on nil did not return 0")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expNonsense := 0
 | 
			
		||||
	inNonsense := "string?"
 | 
			
		||||
	outNonsense := KeyLength(inNonsense)
 | 
			
		||||
	if expNonsense != outNonsense {
 | 
			
		||||
		t.Fatal("KeyLength malfunctioning on nonsense input")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//test the ecdsa branch
 | 
			
		||||
	ecdsaPriv, _ := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
 | 
			
		||||
	ecdsaIn, _ := ecdsaPriv.Public().(*ecdsa.PublicKey)
 | 
			
		||||
	expEcdsa := ecdsaIn.Curve.Params().BitSize
 | 
			
		||||
	outEcdsa := KeyLength(ecdsaIn)
 | 
			
		||||
	if expEcdsa != outEcdsa {
 | 
			
		||||
		t.Fatal("KeyLength malfunctioning on ecdsa input")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//test the rsa branch
 | 
			
		||||
	rsaPriv, _ := rsa.GenerateKey(rand.Reader, 256)
 | 
			
		||||
	rsaIn, _ := rsaPriv.Public().(*rsa.PublicKey)
 | 
			
		||||
	expRsa := rsaIn.N.BitLen()
 | 
			
		||||
	outRsa := KeyLength(rsaIn)
 | 
			
		||||
 | 
			
		||||
	if expRsa != outRsa {
 | 
			
		||||
		t.Fatal("KeyLength malfunctioning on rsa input")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestExpiryTime(t *testing.T) {
 | 
			
		||||
	// nil case
 | 
			
		||||
	var expNil *time.Time
 | 
			
		||||
	inNil := []*x509.Certificate{}
 | 
			
		||||
	outNil := ExpiryTime(inNil)
 | 
			
		||||
	if expNil != outNil {
 | 
			
		||||
		t.Fatal("Expiry time is malfunctioning on empty input")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//read a pem file and use that expiry date
 | 
			
		||||
	bytes, _ := ioutil.ReadFile(testBundleFile)
 | 
			
		||||
	certs, err := ParseCertificatesPEM(bytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
	expected := time.Date(2014, time.April, 15, 0, 0, 0, 0, time.UTC)
 | 
			
		||||
	out := ExpiryTime(certs)
 | 
			
		||||
	if out == nil {
 | 
			
		||||
		t.Fatal("Expiry time returning null")
 | 
			
		||||
	}
 | 
			
		||||
	if *out != expected {
 | 
			
		||||
		t.Fatalf("Expected %v, got %v", expected, *out)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHashAlgoString(t *testing.T) {
 | 
			
		||||
	if HashAlgoString(x509.MD2WithRSA) != "MD2" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.MD5WithRSA) != "MD5" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.SHA1WithRSA) != "SHA1" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.SHA256WithRSA) != "SHA256" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.SHA384WithRSA) != "SHA384" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.SHA512WithRSA) != "SHA512" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.DSAWithSHA1) != "SHA1" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.DSAWithSHA256) != "SHA256" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.ECDSAWithSHA1) != "SHA1" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.ECDSAWithSHA256) != "SHA256" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.ECDSAWithSHA384) != "SHA384" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(x509.ECDSAWithSHA512) != "SHA512" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
	if HashAlgoString(math.MaxInt32) != "Unknown Hash Algorithm" {
 | 
			
		||||
		t.Fatal("standin")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSignatureString(t *testing.T) {
 | 
			
		||||
	if SignatureString(x509.MD2WithRSA) != "MD2WithRSA" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.MD5WithRSA) != "MD5WithRSA" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.SHA1WithRSA) != "SHA1WithRSA" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.SHA256WithRSA) != "SHA256WithRSA" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.SHA384WithRSA) != "SHA384WithRSA" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.SHA512WithRSA) != "SHA512WithRSA" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.DSAWithSHA1) != "DSAWithSHA1" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.DSAWithSHA256) != "DSAWithSHA256" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.ECDSAWithSHA1) != "ECDSAWithSHA1" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.ECDSAWithSHA256) != "ECDSAWithSHA256" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.ECDSAWithSHA384) != "ECDSAWithSHA384" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(x509.ECDSAWithSHA512) != "ECDSAWithSHA512" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
	if SignatureString(math.MaxInt32) != "Unknown Signature" {
 | 
			
		||||
		t.Fatal("Signature String functioning improperly")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseCertificatePEM(t *testing.T) {
 | 
			
		||||
	for _, testFile := range []string{testCertFile, testExtraWSCertFile} {
 | 
			
		||||
		certPEM, err := ioutil.ReadFile(testFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, err := ParseCertificatePEM(certPEM); err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, testFile := range []string{testBundleFile, testMessedUpCertFile, testEmptyCertFile} {
 | 
			
		||||
		certPEM, err := ioutil.ReadFile(testFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, err := ParseCertificatePEM(certPEM); err == nil {
 | 
			
		||||
			t.Fatal("Incorrect cert failed to raise error")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseCertificatesPEM(t *testing.T) {
 | 
			
		||||
	// expected cases
 | 
			
		||||
	for _, testFile := range []string{testBundleFile, testExtraWSBundleFile} {
 | 
			
		||||
		bundlePEM, err := ioutil.ReadFile(testFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, err := ParseCertificatesPEM(bundlePEM); err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// test failure cases
 | 
			
		||||
	// few lines deleted, then headers removed
 | 
			
		||||
	for _, testFile := range []string{testMessedUpBundleFile, testNoHeaderCert} {
 | 
			
		||||
		bundlePEM, err := ioutil.ReadFile(testFile)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, err := ParseCertificatesPEM(bundlePEM); err == nil {
 | 
			
		||||
			t.Fatal("Incorrectly-formatted file failed to produce an error")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSelfSignedCertificatePEM(t *testing.T) {
 | 
			
		||||
	testPEM, _ := ioutil.ReadFile(testCertFile)
 | 
			
		||||
	_, err := ParseSelfSignedCertificatePEM(testPEM)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// a few lines deleted from the pem file
 | 
			
		||||
	wrongPEM, _ := ioutil.ReadFile(testMessedUpCertFile)
 | 
			
		||||
	_, err2 := ParseSelfSignedCertificatePEM(wrongPEM)
 | 
			
		||||
	if err2 == nil {
 | 
			
		||||
		t.Fatal("Improper pem file failed to raise an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// alter the signature of a valid certificate
 | 
			
		||||
	blk, _ := pem.Decode(testPEM)
 | 
			
		||||
	blk.Bytes[len(blk.Bytes)-10]++ // some hacking to get to the sig
 | 
			
		||||
	alteredBytes := pem.EncodeToMemory(blk)
 | 
			
		||||
	_, err = ParseSelfSignedCertificatePEM(alteredBytes)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Incorrect cert failed to produce an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParsePrivateKeyPEM(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	// expected case
 | 
			
		||||
	testPEM, _ := ioutil.ReadFile(testPrivateKey)
 | 
			
		||||
	_, err := ParsePrivateKeyPEM(testPEM)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// error cases
 | 
			
		||||
	errCases := []string{
 | 
			
		||||
		testMessedUpPrivateKey,  // a few lines deleted
 | 
			
		||||
		testEmptyPem,            //empty file
 | 
			
		||||
		testEncryptedPrivateKey, // encrypted key
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, fname := range errCases {
 | 
			
		||||
		testPEM, _ = ioutil.ReadFile(fname)
 | 
			
		||||
		_, err = ParsePrivateKeyPEM(testPEM)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			t.Fatal("Incorrect private key failed to produce an error")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										53
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
 | 
			
		||||
EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp
 | 
			
		||||
bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
 | 
			
		||||
cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw
 | 
			
		||||
MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
 | 
			
		||||
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
 | 
			
		||||
DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs
 | 
			
		||||
b3VkZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGw
 | 
			
		||||
f3F0XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73P
 | 
			
		||||
IXGyfNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGF
 | 
			
		||||
MA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB
 | 
			
		||||
+YoiUjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOS
 | 
			
		||||
FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B
 | 
			
		||||
AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd
 | 
			
		||||
FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF
 | 
			
		||||
A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j
 | 
			
		||||
4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c
 | 
			
		||||
WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT
 | 
			
		||||
br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs
 | 
			
		||||
369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh
 | 
			
		||||
PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw
 | 
			
		||||
EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS
 | 
			
		||||
/mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH
 | 
			
		||||
0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT
 | 
			
		||||
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv
 | 
			
		||||
MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG
 | 
			
		||||
A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw
 | 
			
		||||
MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE
 | 
			
		||||
CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET
 | 
			
		||||
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j
 | 
			
		||||
b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL
 | 
			
		||||
AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng
 | 
			
		||||
xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW
 | 
			
		||||
RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu
 | 
			
		||||
u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU
 | 
			
		||||
mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0
 | 
			
		||||
APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys
 | 
			
		||||
sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT
 | 
			
		||||
7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7
 | 
			
		||||
STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow
 | 
			
		||||
TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND
 | 
			
		||||
DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS
 | 
			
		||||
BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH
 | 
			
		||||
EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj
 | 
			
		||||
bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/
 | 
			
		||||
fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9
 | 
			
		||||
fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch
 | 
			
		||||
DaMsXjQQTJu0iuG3qKEuCmUwOmc=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										56
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/bundle_with_whitespace.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										56
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/bundle_with_whitespace.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
    
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
 | 
			
		||||
EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp
 | 
			
		||||
bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
 | 
			
		||||
cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw
 | 
			
		||||
MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
 | 
			
		||||
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
 | 
			
		||||
DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNs
 | 
			
		||||
b3VkZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGw
 | 
			
		||||
f3F0XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73P
 | 
			
		||||
IXGyfNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGF
 | 
			
		||||
MA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB
 | 
			
		||||
+YoiUjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOS
 | 
			
		||||
FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B
 | 
			
		||||
AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd
 | 
			
		||||
FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF
 | 
			
		||||
A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j
 | 
			
		||||
4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c
 | 
			
		||||
WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT
 | 
			
		||||
br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs
 | 
			
		||||
369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh
 | 
			
		||||
PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw
 | 
			
		||||
EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS
 | 
			
		||||
/mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH
 | 
			
		||||
0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT
 | 
			
		||||
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv
 | 
			
		||||
MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG
 | 
			
		||||
A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw
 | 
			
		||||
MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE
 | 
			
		||||
CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET
 | 
			
		||||
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j
 | 
			
		||||
b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL
 | 
			
		||||
AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng
 | 
			
		||||
xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW
 | 
			
		||||
RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu
 | 
			
		||||
u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU
 | 
			
		||||
mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0
 | 
			
		||||
APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys
 | 
			
		||||
sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT
 | 
			
		||||
7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7
 | 
			
		||||
STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow
 | 
			
		||||
TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND
 | 
			
		||||
DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS
 | 
			
		||||
BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH
 | 
			
		||||
EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj
 | 
			
		||||
bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/
 | 
			
		||||
fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9
 | 
			
		||||
fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch
 | 
			
		||||
DaMsXjQQTJu0iuG3qKEuCmUwOmc=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/cert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/cert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
 | 
			
		||||
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy
 | 
			
		||||
MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd
 | 
			
		||||
MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C
 | 
			
		||||
MS59jJOLomfDnKUWOGKi/k7URBg1HNL3vm7/ESDazZWFy9l/nibWxNkSUPkQIrvr
 | 
			
		||||
GsNivkRUzXkwgNX8IN8LOYAQ3BWxAqitXTpLjf4FeCTB6G59v9eYlAX3kicXRdY+
 | 
			
		||||
cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME
 | 
			
		||||
MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m
 | 
			
		||||
dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi
 | 
			
		||||
uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O
 | 
			
		||||
aq+K7aVrgHkPnWeRiG6tl+ZA
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										15
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/cert_with_whitespace.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										15
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/cert_with_whitespace.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
 | 
			
		||||
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy
 | 
			
		||||
MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd
 | 
			
		||||
MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C
 | 
			
		||||
MS59jJOLomfDnKUWOGKi/k7URBg1HNL3vm7/ESDazZWFy9l/nibWxNkSUPkQIrvr
 | 
			
		||||
GsNivkRUzXkwgNX8IN8LOYAQ3BWxAqitXTpLjf4FeCTB6G59v9eYlAX3kicXRdY+
 | 
			
		||||
cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME
 | 
			
		||||
MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m
 | 
			
		||||
dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi
 | 
			
		||||
uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O
 | 
			
		||||
aq+K7aVrgHkPnWeRiG6tl+ZA
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
   
 | 
			
		||||
							
								
								
									
										1
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/empty.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										1
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/empty.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
 | 
			
		||||
							
								
								
									
										2
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/emptycert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										2
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/emptycert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
-----END CERTIFICATE-----LSKFSKLF
 | 
			
		||||
							
								
								
									
										30
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/enc_priv_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										30
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/enc_priv_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
Proc-Type: 4,ENCRYPTED
 | 
			
		||||
DEK-Info: AES-128-CBC,90B8A5792FA2FE75B2053582F3DF394F
 | 
			
		||||
 | 
			
		||||
yVY2xuth5fdJBg9gg+6eP3qTsr0CJ2mGEDW6rvYmYuATSRF1hVERrsznxJYjYLaw
 | 
			
		||||
JHec8FVr78y4aXxI/aFzlxLkS8f12WjTtIhzHwhzgSJDwVOXSRphnLAeHWnhEKLe
 | 
			
		||||
7kO+vzoTPIc3ECwdvtr6//z2tP1/sac+yIhL6C+x2rS5hFHhmDUXtILPxxfHJCiM
 | 
			
		||||
qtKiiOZz3W6008CeJMC9ZPlKHDvpq7aIL4rfVP/GkZ+/teQkgWNpMxac7+gWLKuK
 | 
			
		||||
109v6pu+8KT49D6SMsaZPvAb5PXcIB79ZCPI1JX0V26CKcswba4RHG/h1xifwyAF
 | 
			
		||||
OIvmK29mmFqbx5GPlUefRUuPwRJKCXFiK6LTdhCwLYodtXde4ibvOFYy4onGoVax
 | 
			
		||||
I5WVaOhQMqp+mxA6z7odrIvuFcQGixIA+peaaSbpNZSZGuxRvVefcdxPbJ+26Ijs
 | 
			
		||||
wq8uyalbwhKtjPTPNkMaaYzJdWS7wd2DS4RM9JT8Y1h6NTftCY3c+/txOlt5pQzW
 | 
			
		||||
T8n+NTd4o+PFOHzMnmEnrtf9Y/SSzXDB2OPCD95YdIXItQDdKcjK0NmnY8GNfkWL
 | 
			
		||||
G30NJNy3/DR7Sa5u4xuqNgcgTFhgZaOQ1IVB3p5VjknqAX3gWFu2DrqzbH45071A
 | 
			
		||||
He7VbdbzBpMHI2EdiCVOuK9fD/5sv25u9vVC2NHtG/YcoEQv+RB52TNHn9kdiMj1
 | 
			
		||||
gLaywPqGjFmaPxI0xX07BrL+D9RruUT1GAEyw4JAHuJZIyq3+V98wmV/pEqwc7hp
 | 
			
		||||
8WuSi6YddetfF4NPA5cGWt8qZ1it+wD/1ydQEAQsxdANqi0XVudYpYox02EoRS02
 | 
			
		||||
up0sd9zqz83pN9RyOOKtGcHdt85gb9DYRVeff1UszMaoVULxqxYetwtzpiHn6grL
 | 
			
		||||
DmnSk+DYgvXKOVt8tmSJysDTumhK1VN3xb34TYYJxeBOQJLzWFjGSELEpphZAQSj
 | 
			
		||||
rS4OM1FwoP48wvASGiWD4VUJ6v+6F+NDvJr01S+zWGLg1EeUZJmXGHW5GrGd4Kgx
 | 
			
		||||
3rdeOsrED9oXKp2cpgx9avXJ9upixja9MbAPp7RkSyeHMPvsuaI44xvOP3f0crmG
 | 
			
		||||
d/5CdBKVT7nFaeTGSx/78kHb3VJyopAMm9k0V3CheKwBXXSbXmV1+0muBxMHsEI3
 | 
			
		||||
aEKaI0y5cDfTewzo/U0l0kGtxF6kUPN1pdjFpAvssRlkGttFOC2nWxHwaNHpn7Kq
 | 
			
		||||
gFAlN6P4cyB6kb+LvckIYTZ/tV39dx7PfL0KG5TWjJ4a9GSoL1IrAhQq+Qv6oUEt
 | 
			
		||||
1vlejZoKyZ/35fni0fmeYNho+pCPimm6l+sHTuXkrWgGLr0S9O00HFLz11D7R4o9
 | 
			
		||||
7mF4JkMNztT+ENOdT4xQBi3OGjRGMwtE6PsQPfDeu13Vq6eDtdEGUdhW1kAsGnBi
 | 
			
		||||
eJRuysnGpnoWofJ7yS0+DhnS4GAVi907TMrQWwmez9V4CXl4NBc8X9T69TFL2LsW
 | 
			
		||||
2KU9NUXdiCRZqZHD41gd3+RuRA/oXh50V9oaow+uepwYKTFyzde5IH1/DgBd7tOd
 | 
			
		||||
Fa2fM5/zSA0uFPRb3yCVhRg5d6J9t5yaPAz7Jp0D1mDDGsMBD1O/FYJvWoANEwUX
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										48
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/messed_up_bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										48
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/messed_up_bundle.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEczCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
 | 
			
		||||
EwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdp
 | 
			
		||||
bmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZv
 | 
			
		||||
cm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAw
 | 
			
		||||
MDAwWhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
 | 
			
		||||
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
 | 
			
		||||
FHsHEDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0B
 | 
			
		||||
AQsDggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJd
 | 
			
		||||
FI1UjL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHF
 | 
			
		||||
A145JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j
 | 
			
		||||
4WCv5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7c
 | 
			
		||||
WWOay6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvT
 | 
			
		||||
br6+bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs
 | 
			
		||||
369/Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2Ygh
 | 
			
		||||
PsypDo33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpw
 | 
			
		||||
EPVqTR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS
 | 
			
		||||
/mg1t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH
 | 
			
		||||
0thnUGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuT
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEkDCCA/ugAwIBAgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYT
 | 
			
		||||
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2Nv
 | 
			
		||||
MRMwEQYDVQQKDApDbG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQG
 | 
			
		||||
A1UEAwwNQ0ZTU0xfVEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAw
 | 
			
		||||
MDBaMIGMMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UE
 | 
			
		||||
CxMTU3lzdGVtcyBFbmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzET
 | 
			
		||||
MBEGA1UECBMKQ2FsaWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5j
 | 
			
		||||
b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHL
 | 
			
		||||
AlI+xwnPhWgzj2VevD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0Ng
 | 
			
		||||
xxwQ2rC08fJtCnijlGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeW
 | 
			
		||||
RbWuLH5nEMdyk9NpetS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fu
 | 
			
		||||
u6pgMtHKvl4GGH0yvb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREU
 | 
			
		||||
mlcY5EvpR141KXbZqiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0
 | 
			
		||||
APJx1VNSSH6XoDpUETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsys
 | 
			
		||||
sWBEN+CxK19xyPumr21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT
 | 
			
		||||
7r3mzlBTYl3poU26q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7
 | 
			
		||||
STOs8wuTu3huSnan/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuow
 | 
			
		||||
TmmHlb8KIMa9mOvcuGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VND
 | 
			
		||||
DL3J/vSVlFeqLt2reAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDAS
 | 
			
		||||
BgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsH
 | 
			
		||||
EDAfBgNVHSMEGDAWgBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRj
 | 
			
		||||
bG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/
 | 
			
		||||
fWznVvOEFAAYZByPFx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9
 | 
			
		||||
fC7vf45B2zCX0OW51QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnch
 | 
			
		||||
DaMsXjQQTJu0iuG3qKEuCmUwOmc=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
SDFSDKjkfdlsdfj
 | 
			
		||||
							
								
								
									
										20
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/messed_up_priv_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										20
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/messed_up_priv_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEowIBAAKCAQEAvGKyz9ZzIXI/BFrtqbVQMmKQkPZGndyfV3AzeSb2ulbS/s5k
 | 
			
		||||
yNJMH/jKZiSCvZiJNnW+JNlJrgLxORMmPStPz/N/0L0vCTotQKZUiaBttFgHgobQ
 | 
			
		||||
LFsbMnumt9It5W/uOwgWI9binuzvqyPXywLlYwOq3jkOmA22ymhflzRrl6a3jzcY
 | 
			
		||||
hT9evxHl0gV4bN7KZ5p4wK/UUuG1uMEQLw87lUwRRHeW3ZG52VL38+redka+f5pa
 | 
			
		||||
SGKyG5j0oe1NPLqAjckNgqvDdPMY2gicmCq0VSLzTNpHRsURTUSJvC/iv34vVfba
 | 
			
		||||
gIYgTvm8BvGbJSlZqP4kEVlOfd3vmB0ttUeoDwIDAQABAoIBAHZdpXCFlA1d1U6N
 | 
			
		||||
O2s4a01dNOyAcVpa9xtfelgTLU9jomtLj3PG/uHP1oxbQHKUVxKK5JAOnwbg/mQY
 | 
			
		||||
LhydDCbjHlovpFAt56UJXXCkBoocDYvr3P0huXL80oIJY6EXtR4ONKsMJ5Qn12c2
 | 
			
		||||
vC3ogey2rzO1sf/EDigbcIR3AWtk1Tx8ZDUooktOFypIsDQgjjxXiURGssAlMPSh
 | 
			
		||||
6GVgO4JRRG6oRxEna7yDe7izmh/hC5sxSYLsEikCgYEAsBHhb/Qef5obRCSrfFuQ
 | 
			
		||||
41P7MCtGrXVxKD3iCDGQCzVbEbYGpmZnGsXSaHljp2FtnamaGGEudYziozGKPHjs
 | 
			
		||||
pbTbsLIDbmNwxz1WcaZ1iyIjtOxcAEqDod8hY4hL6SaxypwTHn4Ydbw2NGzp11Eg
 | 
			
		||||
Di4SVL82utjycATdKFvBzdsCgYB/3M+GMrt0Sh87rKcQLdL709Kzjcfhvm4HjIbJ
 | 
			
		||||
GSXGPCZaYMKaXRTdNAjtRKxMawc9qcf0xSBEHL0GkB158TzusDQtjP1anTcYOnl6
 | 
			
		||||
GsO4bRivp314iNlP4r3S3bIXqBxCGH3HbrvpdPFAN//qjYmAki2lFQZywfvbQOE8
 | 
			
		||||
oFQHwQKBgHqJkTck2DGlXQIwA7jirLggISXjSPlsG4w4LuhY9ivyNKLUi4x5k1cE
 | 
			
		||||
bX7SrRtJErQ1WaDN4TFG25xnysi5h+aPinuySatd0XmA5+dE1YjTqqShMO+lUpzi
 | 
			
		||||
PrOQl6Eva/uw5BDAcUH4AaXTNRvvtXQptUil9qXyOh6fszikA9Mm
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/messedupcert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/messedupcert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
 | 
			
		||||
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy
 | 
			
		||||
MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd
 | 
			
		||||
MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C
 | 
			
		||||
cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME
 | 
			
		||||
MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m
 | 
			
		||||
dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi
 | 
			
		||||
uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O
 | 
			
		||||
aq+K7aVrgHkPnWeRiG6tl+ZA
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										9
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/noheadercert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										9
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/noheadercert.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
MIIB7jCCAVmgAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
 | 
			
		||||
bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTEyMDkwNzIyMDAwNFoXDTEzMDkwNzIy
 | 
			
		||||
MDUwNFowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGd
 | 
			
		||||
MAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEAm6f+jkP2t5q/vM0YAUZZkhq/EAYD+L1C
 | 
			
		||||
cqhEvLFbu3MCAwEAAaMyMDAwDgYDVR0PAQH/BAQDAgCgMA0GA1UdDgQGBAQBAgME
 | 
			
		||||
MA8GA1UdIwQIMAaABAECAwQwCwYJKoZIhvcNAQEFA4GBABndWRIcfi+QB9Sakr+m
 | 
			
		||||
dYnXTgYCnFio53L2Z+6EHTGG+rEhWtUEGhL4p4pzXX4siAnjWvwcgXTo92cafcfi
 | 
			
		||||
uB7wRfK+NL9CTJdpN6cdL+fiNHzH8hsl3bj1nL0CSmdn2hkUWVLbLhSgWlib/I8O
 | 
			
		||||
aq+K7aVrgHkPnWeRiG6tl+ZA
 | 
			
		||||
							
								
								
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/priv_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers/testdata/priv_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEowIBAAKCAQEAvGKyz9ZzIXI/BFrtqbVQMmKQkPZGndyfV3AzeSb2ulbS/s5k
 | 
			
		||||
yNJMH/jKZiSCvZiJNnW+JNlJrgLxORMmPStPz/N/0L0vCTotQKZUiaBttFgHgobQ
 | 
			
		||||
LFsbMnumt9It5W/uOwgWI9binuzvqyPXywLlYwOq3jkOmA22ymhflzRrl6a3jzcY
 | 
			
		||||
hT9evxHl0gV4bN7KZ5p4wK/UUuG1uMEQLw87lUwRRHeW3ZG52VL38+redka+f5pa
 | 
			
		||||
SGKyG5j0oe1NPLqAjckNgqvDdPMY2gicmCq0VSLzTNpHRsURTUSJvC/iv34vVfba
 | 
			
		||||
gIYgTvm8BvGbJSlZqP4kEVlOfd3vmB0ttUeoDwIDAQABAoIBAHZdpXCFlA1d1U6N
 | 
			
		||||
O2s4a01dNOyAcVpa9xtfelgTLU9jomtLj3PG/uHP1oxbQHKUVxKK5JAOnwbg/mQY
 | 
			
		||||
LhydDCbjHlovpFAt56UJXXCkBoocDYvr3P0huXL80oIJY6EXtR4ONKsMJ5Qn12c2
 | 
			
		||||
vC3ogey2rzO1sf/EDigbcIR3AWtk1Tx8ZDUooktOFypIsDQgjjxXiURGssAlMPSh
 | 
			
		||||
1BFz4StRUK4bESaja0GiHwbuxHa+XYEBlK5OqMo/fpWqpgHhV/42+7wdcBMJsMr8
 | 
			
		||||
rFBe6m+r6TTbLSGJNowyd05XrjoAI35qduckpJ3Voun90i4ynTudjdJ/vHpIqB74
 | 
			
		||||
qQLFW2ECgYEA+GSRVqobaKKakNUFGmK0I5T5Tikz5f137YXXER6aLtDQNiSrlXNi
 | 
			
		||||
0aphkC/EfRO3oNvamq5+55bmmgDVoNNPDfpajKz+LZyG8GC2EXlTKO0hZS64KRRl
 | 
			
		||||
C+bd+ZsYiUDImNVRbIHN82f+BQgsgXlTaWpBOrEqmoePO/J44O4eX3cCgYEAwieq
 | 
			
		||||
amY4UaY+MhWPJFRK1y9M3hM8+N9N/35CFewQUdFJosC6vVQ4t8jNkSOxVQdgbNwE
 | 
			
		||||
i/bTBgIwg82JJYbBUPuCVeTT3i6zxymf/FLumrI73URD81IN6FiH1skg0hSFrvs0
 | 
			
		||||
6GVgO4JRRG6oRxEna7yDe7izmh/hC5sxSYLsEikCgYEAsBHhb/Qef5obRCSrfFuQ
 | 
			
		||||
41P7MCtGrXVxKD3iCDGQCzVbEbYGpmZnGsXSaHljp2FtnamaGGEudYziozGKPHjs
 | 
			
		||||
pbTbsLIDbmNwxz1WcaZ1iyIjtOxcAEqDod8hY4hL6SaxypwTHn4Ydbw2NGzp11Eg
 | 
			
		||||
Di4SVL82utjycATdKFvBzdsCgYB/3M+GMrt0Sh87rKcQLdL709Kzjcfhvm4HjIbJ
 | 
			
		||||
GSXGPCZaYMKaXRTdNAjtRKxMawc9qcf0xSBEHL0GkB158TzusDQtjP1anTcYOnl6
 | 
			
		||||
GsO4bRivp314iNlP4r3S3bIXqBxCGH3HbrvpdPFAN//qjYmAki2lFQZywfvbQOE8
 | 
			
		||||
oFQHwQKBgHqJkTck2DGlXQIwA7jirLggISXjSPlsG4w4LuhY9ivyNKLUi4x5k1cE
 | 
			
		||||
bX7SrRtJErQ1WaDN4TFG25xnysi5h+aPinuySatd0XmA5+dE1YjTqqShMO+lUpzi
 | 
			
		||||
PrOQl6Eva/uw5BDAcUH4AaXTNRvvtXQptUil9qXyOh6fszikA9Mm
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,98 @@
 | 
			
		|||
// Package log implements a wrapper around the Go standard library's
 | 
			
		||||
// logging package. Clients should set the current log level; only
 | 
			
		||||
// messages below that level will actually be logged. For example, if
 | 
			
		||||
// Level is set to LevelWarning, only log messages at the Warning,
 | 
			
		||||
// Error, and Critical levels will be logged.
 | 
			
		||||
package log
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	golog "log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The following constants represent logging levels in increasing levels of seriousness.
 | 
			
		||||
const (
 | 
			
		||||
	LevelDebug = iota
 | 
			
		||||
	LevelInfo
 | 
			
		||||
	LevelWarning
 | 
			
		||||
	LevelError
 | 
			
		||||
	LevelCritical
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var levelPrefix = [...]string{
 | 
			
		||||
	LevelDebug:    "[DEBUG] ",
 | 
			
		||||
	LevelInfo:     "[INFO] ",
 | 
			
		||||
	LevelWarning:  "[WARNING] ",
 | 
			
		||||
	LevelError:    "[ERROR] ",
 | 
			
		||||
	LevelCritical: "[CRITICAL] ",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Level stores the current logging level.
 | 
			
		||||
var Level = LevelDebug
 | 
			
		||||
 | 
			
		||||
func outputf(l int, format string, v []interface{}) {
 | 
			
		||||
	if l >= Level {
 | 
			
		||||
		golog.Printf(fmt.Sprint(levelPrefix[l], format), v...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func output(l int, v []interface{}) {
 | 
			
		||||
	if l >= Level {
 | 
			
		||||
		golog.Print(levelPrefix[l], fmt.Sprint(v...))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Criticalf logs a formatted message at the "critical" level. The
 | 
			
		||||
// arguments are handled in the same manner as fmt.Printf.
 | 
			
		||||
func Criticalf(format string, v ...interface{}) {
 | 
			
		||||
	outputf(LevelCritical, format, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Critical logs its arguments at the "critical" level.
 | 
			
		||||
func Critical(v ...interface{}) {
 | 
			
		||||
	output(LevelCritical, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Errorf logs a formatted message at the "error" level. The arguments
 | 
			
		||||
// are handled in the same manner as fmt.Printf.
 | 
			
		||||
func Errorf(format string, v ...interface{}) {
 | 
			
		||||
	outputf(LevelError, format, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error logs its arguments at the "error" level.
 | 
			
		||||
func Error(v ...interface{}) {
 | 
			
		||||
	output(LevelError, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warningf logs a formatted message at the "warning" level. The
 | 
			
		||||
// arguments are handled in the same manner as fmt.Printf.
 | 
			
		||||
func Warningf(format string, v ...interface{}) {
 | 
			
		||||
	outputf(LevelWarning, format, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Warning logs its arguments at the "warning" level.
 | 
			
		||||
func Warning(v ...interface{}) {
 | 
			
		||||
	output(LevelWarning, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Infof logs a formatted message at the "info" level. The arguments
 | 
			
		||||
// are handled in the same manner as fmt.Printf.
 | 
			
		||||
func Infof(format string, v ...interface{}) {
 | 
			
		||||
	outputf(LevelInfo, format, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info logs its arguments at the "info" level.
 | 
			
		||||
func Info(v ...interface{}) {
 | 
			
		||||
	output(LevelInfo, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debugf logs a formatted message at the "debug" level. The arguments
 | 
			
		||||
// are handled in the same manner as fmt.Printf.
 | 
			
		||||
func Debugf(format string, v ...interface{}) {
 | 
			
		||||
	outputf(LevelDebug, format, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Debug logs its arguments at the "debug" level.
 | 
			
		||||
func Debug(v ...interface{}) {
 | 
			
		||||
	output(LevelDebug, v)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
package log
 | 
			
		||||
							
								
								
									
										165
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/local.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										165
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/local.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,165 @@
 | 
			
		|||
// Package local implements certificate signature functionality for CF-SSL.
 | 
			
		||||
package local
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Signer contains a signer that uses the standard library to
 | 
			
		||||
// support both ECDSA and RSA CA keys.
 | 
			
		||||
type Signer struct {
 | 
			
		||||
	ca      *x509.Certificate
 | 
			
		||||
	priv    crypto.Signer
 | 
			
		||||
	policy  *config.Signing
 | 
			
		||||
	sigAlgo x509.SignatureAlgorithm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSigner creates a new Signer directly from a
 | 
			
		||||
// private key and certificate, with optional policy.
 | 
			
		||||
func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.SignatureAlgorithm, policy *config.Signing) (*Signer, error) {
 | 
			
		||||
	if policy == nil {
 | 
			
		||||
		policy = &config.Signing{
 | 
			
		||||
			Profiles: map[string]*config.SigningProfile{},
 | 
			
		||||
			Default:  config.DefaultConfig()}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !policy.Valid() {
 | 
			
		||||
		return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Signer{
 | 
			
		||||
		ca:      cert,
 | 
			
		||||
		priv:    priv,
 | 
			
		||||
		sigAlgo: sigAlgo,
 | 
			
		||||
		policy:  policy,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSignerFromFile generates a new local signer from a caFile
 | 
			
		||||
// and a caKey file, both PEM encoded.
 | 
			
		||||
func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) {
 | 
			
		||||
	log.Debug("Loading CA: ", caFile)
 | 
			
		||||
	ca, err := ioutil.ReadFile(caFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	log.Debug("Loading CA key: ", caKeyFile)
 | 
			
		||||
	cakey, err := ioutil.ReadFile(caKeyFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parsedCa, err := helpers.ParseCertificatePEM(ca)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priv, err := helpers.ParsePrivateKeyPEM(cakey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Debug("Malformed private key %v", err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
 | 
			
		||||
	err = signer.FillTemplate(template, s.policy.Default, profile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serialNumber := template.SerialNumber
 | 
			
		||||
	var initRoot bool
 | 
			
		||||
	if s.ca == nil {
 | 
			
		||||
		if !template.IsCA {
 | 
			
		||||
			err = cferr.New(cferr.PolicyError, cferr.InvalidRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		template.DNSNames = nil
 | 
			
		||||
		s.ca = template
 | 
			
		||||
		initRoot = true
 | 
			
		||||
		template.MaxPathLen = signer.MaxPathLen
 | 
			
		||||
	} else if template.IsCA {
 | 
			
		||||
		template.MaxPathLen = 1
 | 
			
		||||
		template.DNSNames = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if initRoot {
 | 
			
		||||
		s.ca, err = x509.ParseCertificate(derBytes)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			err = cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
 | 
			
		||||
	log.Infof("signed certificate with serial number %s", serialNumber)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sign signs a new certificate based on the PEM-encoded client
 | 
			
		||||
// certificate or certificate request with the signing profile,
 | 
			
		||||
// specified by profileName.
 | 
			
		||||
func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 | 
			
		||||
	profile := s.policy.Profiles[req.Profile]
 | 
			
		||||
	if profile == nil {
 | 
			
		||||
		profile = s.policy.Default
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block, _ := pem.Decode([]byte(req.Request))
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if block.Type != "CERTIFICATE REQUEST" {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.CertificateError,
 | 
			
		||||
			cferr.BadRequest, errors.New("not a certificate or csr"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template, err := signer.ParseCertificateRequest(s, block.Bytes, req.Subject, req.Hosts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s.sign(template, profile)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SigAlgo returns the RSA signer's signature algorithm.
 | 
			
		||||
func (s *Signer) SigAlgo() x509.SignatureAlgorithm {
 | 
			
		||||
	return s.sigAlgo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Certificate returns the signer's certificate.
 | 
			
		||||
func (s *Signer) Certificate(label, profile string) (*x509.Certificate, error) {
 | 
			
		||||
	if label != "" {
 | 
			
		||||
		return nil, cferr.NewBadRequestString("label specified for local operation")
 | 
			
		||||
	}
 | 
			
		||||
	cert := *s.ca
 | 
			
		||||
	return &cert, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetPolicy sets the signer's signature policy.
 | 
			
		||||
func (s *Signer) SetPolicy(policy *config.Signing) {
 | 
			
		||||
	s.policy = policy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Policy returns the signer's policy.
 | 
			
		||||
func (s *Signer) Policy() *config.Signing {
 | 
			
		||||
	return s.policy
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										555
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/local_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										555
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/local_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,555 @@
 | 
			
		|||
package local
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testCaFile         = "testdata/ca.pem"
 | 
			
		||||
	testCaKeyFile      = "testdata/ca_key.pem"
 | 
			
		||||
	testECDSACaFile    = "testdata/ecdsa256_ca.pem"
 | 
			
		||||
	testECDSACaKeyFile = "testdata/ecdsa256_ca_key.pem"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var expiry = 1 * time.Minute
 | 
			
		||||
 | 
			
		||||
// Start a signer with the testing RSA CA cert and key.
 | 
			
		||||
func newTestSigner(t *testing.T) (s *Signer) {
 | 
			
		||||
	s, err := NewSignerFromFile(testCaFile, testCaKeyFile, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewSignerFromFilePolicy(t *testing.T) {
 | 
			
		||||
	var CAConfig = &config.Config{
 | 
			
		||||
		Signing: &config.Signing{
 | 
			
		||||
			Profiles: map[string]*config.SigningProfile{
 | 
			
		||||
				"signature": &config.SigningProfile{
 | 
			
		||||
					Usage:  []string{"digital signature"},
 | 
			
		||||
					Expiry: expiry,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			Default: &config.SigningProfile{
 | 
			
		||||
				Usage:        []string{"cert sign", "crl sign"},
 | 
			
		||||
				ExpiryString: "43800h",
 | 
			
		||||
				Expiry:       expiry,
 | 
			
		||||
				CA:           true,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	_, err := NewSignerFromFile(testCaFile, testCaKeyFile, CAConfig.Signing)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewSignerFromFileInvalidPolicy(t *testing.T) {
 | 
			
		||||
	var invalidConfig = &config.Config{
 | 
			
		||||
		Signing: &config.Signing{
 | 
			
		||||
			Profiles: map[string]*config.SigningProfile{
 | 
			
		||||
				"invalid": &config.SigningProfile{
 | 
			
		||||
					Usage:  []string{"wiretapping"},
 | 
			
		||||
					Expiry: expiry,
 | 
			
		||||
				},
 | 
			
		||||
				"empty": &config.SigningProfile{},
 | 
			
		||||
			},
 | 
			
		||||
			Default: &config.SigningProfile{
 | 
			
		||||
				Usage:  []string{"digital signature"},
 | 
			
		||||
				Expiry: expiry,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	_, err := NewSignerFromFile(testCaFile, testCaKeyFile, invalidConfig.Signing)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !strings.Contains(err.Error(), `"code":5200`) {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewSignerFromFileNoUsageInPolicy(t *testing.T) {
 | 
			
		||||
	var invalidConfig = &config.Config{
 | 
			
		||||
		Signing: &config.Signing{
 | 
			
		||||
			Profiles: map[string]*config.SigningProfile{
 | 
			
		||||
				"invalid": &config.SigningProfile{
 | 
			
		||||
					Usage:  []string{},
 | 
			
		||||
					Expiry: expiry,
 | 
			
		||||
				},
 | 
			
		||||
				"empty": &config.SigningProfile{},
 | 
			
		||||
			},
 | 
			
		||||
			Default: &config.SigningProfile{
 | 
			
		||||
				Usage:  []string{"digital signature"},
 | 
			
		||||
				Expiry: expiry,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	_, err := NewSignerFromFile(testCaFile, testCaKeyFile, invalidConfig.Signing)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("expect InvalidPolicy error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !strings.Contains(err.Error(), `"code":5200`) {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewSignerFromFileEdgeCases(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	res, err := NewSignerFromFile("nil", "nil", nil)
 | 
			
		||||
	if res != nil && err == nil {
 | 
			
		||||
		t.Fatal("Incorrect inputs failed to produce correct results")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, err = NewSignerFromFile(testCaFile, "nil", nil)
 | 
			
		||||
	if res != nil && err == nil {
 | 
			
		||||
		t.Fatal("Incorrect inputs failed to produce correct results")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, err = NewSignerFromFile("../../helpers/testdata/messedupcert.pem", "local.go", nil)
 | 
			
		||||
	if res != nil && err == nil {
 | 
			
		||||
		t.Fatal("Incorrect inputs failed to produce correct results")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res, err = NewSignerFromFile("../../helpers/testdata/cert.pem", "../../helpers/testdata/messed_up_priv_key.pem", nil)
 | 
			
		||||
	if res != nil && err == nil {
 | 
			
		||||
		t.Fatal("Incorrect inputs failed to produce correct results")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// test the private method
 | 
			
		||||
func testSign(t *testing.T) {
 | 
			
		||||
	signer, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil)
 | 
			
		||||
	if signer == nil || err != nil {
 | 
			
		||||
		t.Fatal("Failed to produce signer")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pem, _ := ioutil.ReadFile("../../helpers/testdata/cert.pem")
 | 
			
		||||
	cert, _ := helpers.ParseCertificatePEM(pem)
 | 
			
		||||
 | 
			
		||||
	badcert := *cert
 | 
			
		||||
	badcert.PublicKey = nil
 | 
			
		||||
	profl := config.SigningProfile{Usage: []string{"Certificates", "Rule"}}
 | 
			
		||||
	_, err = signer.sign(&badcert, &profl)
 | 
			
		||||
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Improper input failed to raise an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// nil profile
 | 
			
		||||
	_, err = signer.sign(cert, &profl)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Nil profile failed to raise an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// empty profile
 | 
			
		||||
	_, err = signer.sign(cert, &config.SigningProfile{})
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Empty profile failed to raise an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// empty expiry
 | 
			
		||||
	prof := signer.policy.Default
 | 
			
		||||
	prof.Expiry = 0
 | 
			
		||||
	_, err = signer.sign(cert, prof)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("nil expiry raised an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// non empty urls
 | 
			
		||||
	prof = signer.policy.Default
 | 
			
		||||
	prof.CRL = "stuff"
 | 
			
		||||
	prof.OCSP = "stuff"
 | 
			
		||||
	prof.IssuerURL = []string{"stuff"}
 | 
			
		||||
	_, err = signer.sign(cert, prof)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("non nil urls raised an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// nil ca
 | 
			
		||||
	nilca := *signer
 | 
			
		||||
	prof = signer.policy.Default
 | 
			
		||||
	prof.CA = false
 | 
			
		||||
	nilca.ca = nil
 | 
			
		||||
	_, err = nilca.sign(cert, prof)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("nil ca with isca false raised an error")
 | 
			
		||||
	}
 | 
			
		||||
	prof.CA = true
 | 
			
		||||
	_, err = nilca.sign(cert, prof)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("nil ca with CA true raised an error")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSign(t *testing.T) {
 | 
			
		||||
	testSign(t)
 | 
			
		||||
	s, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("Failed to produce signer")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// test the empty request
 | 
			
		||||
	_, err = s.Sign(signer.SignRequest{})
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatalf("Empty request failed to produce an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// not a csr
 | 
			
		||||
	certPem, err := ioutil.ReadFile("../../helpers/testdata/cert.pem")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// csr with ip as hostname
 | 
			
		||||
	pem, err := ioutil.ReadFile("testdata/ip.csr")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// improper request
 | 
			
		||||
	validReq := signer.SignRequest{Hosts: signer.SplitHosts(testHostName), Request: string(certPem)}
 | 
			
		||||
	_, err = s.Sign(validReq)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("A bad case failed to raise an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	validReq = signer.SignRequest{Hosts: signer.SplitHosts("128.84.126.213"), Request: string(pem)}
 | 
			
		||||
	_, err = s.Sign(validReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("A bad case failed to raise an error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pem, err = ioutil.ReadFile("testdata/ex.csr")
 | 
			
		||||
	validReq = signer.SignRequest{
 | 
			
		||||
		Request: string(pem),
 | 
			
		||||
		Hosts:   []string{"example.com"},
 | 
			
		||||
	}
 | 
			
		||||
	s.Sign(validReq)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("Failed to sign")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCertificate(t *testing.T) {
 | 
			
		||||
	s, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c, err := s.Certificate("", "")
 | 
			
		||||
	if !reflect.DeepEqual(*c, *s.ca) || err != nil {
 | 
			
		||||
		t.Fatal("Certificate() producing incorrect results")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPolicy(t *testing.T) {
 | 
			
		||||
	s, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sgn := config.Signing{}
 | 
			
		||||
 | 
			
		||||
	s.SetPolicy(&sgn)
 | 
			
		||||
	if s.Policy() != &sgn {
 | 
			
		||||
		t.Fatal("Policy is malfunctioning")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newCustomSigner(t *testing.T, testCaFile, testCaKeyFile string) (s *Signer) {
 | 
			
		||||
	s, err := NewSignerFromFile(testCaFile, testCaKeyFile, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewSignerFromFile(t *testing.T) {
 | 
			
		||||
	newTestSigner(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testHostName = "localhost"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func testSignFile(t *testing.T, certFile string) ([]byte, error) {
 | 
			
		||||
	s := newTestSigner(t)
 | 
			
		||||
 | 
			
		||||
	pem, err := ioutil.ReadFile(certFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(testHostName), Request: string(pem)})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type csrTest struct {
 | 
			
		||||
	file    string
 | 
			
		||||
	keyAlgo string
 | 
			
		||||
	keyLen  int
 | 
			
		||||
	// Error checking function
 | 
			
		||||
	errorCallback func(*testing.T, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A helper function that returns a errorCallback function which expects an error.
 | 
			
		||||
func ExpectError() func(*testing.T, error) {
 | 
			
		||||
	return func(t *testing.T, err error) {
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			t.Fatal("Expected error. Got nothing.")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var csrTests = []csrTest{
 | 
			
		||||
	{
 | 
			
		||||
		file:          "testdata/rsa2048.csr",
 | 
			
		||||
		keyAlgo:       "rsa",
 | 
			
		||||
		keyLen:        2048,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "testdata/rsa3072.csr",
 | 
			
		||||
		keyAlgo:       "rsa",
 | 
			
		||||
		keyLen:        3072,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "testdata/rsa4096.csr",
 | 
			
		||||
		keyAlgo:       "rsa",
 | 
			
		||||
		keyLen:        4096,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "testdata/ecdsa256.csr",
 | 
			
		||||
		keyAlgo:       "ecdsa",
 | 
			
		||||
		keyLen:        256,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "testdata/ecdsa384.csr",
 | 
			
		||||
		keyAlgo:       "ecdsa",
 | 
			
		||||
		keyLen:        384,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "testdata/ecdsa521.csr",
 | 
			
		||||
		keyAlgo:       "ecdsa",
 | 
			
		||||
		keyLen:        521,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSignCSRs(t *testing.T) {
 | 
			
		||||
	s := newTestSigner(t)
 | 
			
		||||
	hostname := "cloudflare.com"
 | 
			
		||||
	for _, test := range csrTests {
 | 
			
		||||
		csr, err := ioutil.ReadFile(test.file)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal("CSR loading error:", err)
 | 
			
		||||
		}
 | 
			
		||||
		// It is possible to use different SHA2 algorithm with RSA CA key.
 | 
			
		||||
		rsaSigAlgos := []x509.SignatureAlgorithm{x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA}
 | 
			
		||||
		for _, sigAlgo := range rsaSigAlgos {
 | 
			
		||||
			s.sigAlgo = sigAlgo
 | 
			
		||||
			certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csr)})
 | 
			
		||||
			if test.errorCallback != nil {
 | 
			
		||||
				test.errorCallback(t, err)
 | 
			
		||||
			} else {
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen)
 | 
			
		||||
				}
 | 
			
		||||
				cert, _ := helpers.ParseCertificatePEM(certBytes)
 | 
			
		||||
				if cert.SignatureAlgorithm != s.SigAlgo() {
 | 
			
		||||
					t.Fatal("Cert Signature Algorithm does not match the issuer.")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestECDSASigner(t *testing.T) {
 | 
			
		||||
	s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile)
 | 
			
		||||
	hostname := "cloudflare.com"
 | 
			
		||||
	for _, test := range csrTests {
 | 
			
		||||
		csr, err := ioutil.ReadFile(test.file)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal("CSR loading error:", err)
 | 
			
		||||
		}
 | 
			
		||||
		// Try all ECDSA SignatureAlgorithm
 | 
			
		||||
		SigAlgos := []x509.SignatureAlgorithm{x509.ECDSAWithSHA1, x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512}
 | 
			
		||||
		for _, sigAlgo := range SigAlgos {
 | 
			
		||||
			s.sigAlgo = sigAlgo
 | 
			
		||||
			certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csr)})
 | 
			
		||||
			if test.errorCallback != nil {
 | 
			
		||||
				test.errorCallback(t, err)
 | 
			
		||||
			} else {
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen)
 | 
			
		||||
				}
 | 
			
		||||
				cert, _ := helpers.ParseCertificatePEM(certBytes)
 | 
			
		||||
				if cert.SignatureAlgorithm != s.SigAlgo() {
 | 
			
		||||
					t.Fatal("Cert Signature Algorithm does not match the issuer.")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ecdsaInterCSR = "testdata/ecdsa256-inter.csr"
 | 
			
		||||
	ecdsaInterKey = "testdata/ecdsa256-inter.key"
 | 
			
		||||
	rsaInterCSR   = "testdata/rsa2048-inter.csr"
 | 
			
		||||
	rsaInterKey   = "testdata/rsa2048-inter.key"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestCAIssuing(t *testing.T) {
 | 
			
		||||
	var caCerts = []string{testCaFile, testECDSACaFile}
 | 
			
		||||
	var caKeys = []string{testCaKeyFile, testECDSACaKeyFile}
 | 
			
		||||
	var interCSRs = []string{ecdsaInterCSR, rsaInterCSR}
 | 
			
		||||
	var interKeys = []string{ecdsaInterKey, rsaInterKey}
 | 
			
		||||
	var CAPolicy = &config.Signing{
 | 
			
		||||
		Default: &config.SigningProfile{
 | 
			
		||||
			Usage:        []string{"cert sign", "crl sign"},
 | 
			
		||||
			ExpiryString: "1h",
 | 
			
		||||
			Expiry:       1 * time.Hour,
 | 
			
		||||
			CA:           true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	var hostname = "cloudflare-inter.com"
 | 
			
		||||
	// Each RSA or ECDSA root CA issues two intermediate CAs (one ECDSA and one RSA).
 | 
			
		||||
	// For each intermediate CA, use it to issue additional RSA and ECDSA intermediate CSRs.
 | 
			
		||||
	for i, caFile := range caCerts {
 | 
			
		||||
		caKeyFile := caKeys[i]
 | 
			
		||||
		s := newCustomSigner(t, caFile, caKeyFile)
 | 
			
		||||
		s.policy = CAPolicy
 | 
			
		||||
		for j, csr := range interCSRs {
 | 
			
		||||
			csrBytes, _ := ioutil.ReadFile(csr)
 | 
			
		||||
			certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csrBytes)})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			interCert, err := helpers.ParseCertificatePEM(certBytes)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			keyBytes, _ := ioutil.ReadFile(interKeys[j])
 | 
			
		||||
			interKey, _ := helpers.ParsePrivateKeyPEM(keyBytes)
 | 
			
		||||
			interSigner := &Signer{interCert, interKey, CAPolicy, signer.DefaultSigAlgo(interKey)}
 | 
			
		||||
			for _, anotherCSR := range interCSRs {
 | 
			
		||||
				anotherCSRBytes, _ := ioutil.ReadFile(anotherCSR)
 | 
			
		||||
				bytes, err := interSigner.Sign(
 | 
			
		||||
					signer.SignRequest{
 | 
			
		||||
						Hosts:   signer.SplitHosts(hostname),
 | 
			
		||||
						Request: string(anotherCSRBytes),
 | 
			
		||||
					})
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					t.Fatal(err)
 | 
			
		||||
				}
 | 
			
		||||
				cert, err := helpers.ParseCertificatePEM(bytes)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					t.Fatal(err)
 | 
			
		||||
				}
 | 
			
		||||
				if cert.SignatureAlgorithm != interSigner.SigAlgo() {
 | 
			
		||||
					t.Fatal("Cert Signature Algorithm does not match the issuer.")
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const testCSR = "testdata/ecdsa256.csr"
 | 
			
		||||
 | 
			
		||||
func TestOverrideSubject(t *testing.T) {
 | 
			
		||||
	csrPEM, err := ioutil.ReadFile(testCSR)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req := &signer.Subject{
 | 
			
		||||
		Names: []csr.Name{
 | 
			
		||||
			{O: "example.net"},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile)
 | 
			
		||||
 | 
			
		||||
	request := signer.SignRequest{
 | 
			
		||||
		Hosts:   []string{"127.0.0.1", "localhost"},
 | 
			
		||||
		Request: string(csrPEM),
 | 
			
		||||
		Subject: req,
 | 
			
		||||
	}
 | 
			
		||||
	certPEM, err := s.Sign(request)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, err := helpers.ParseCertificatePEM(certPEM)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cert.Subject.Organization[0] != "example.net" {
 | 
			
		||||
		t.Fatalf("Failed to override subject: want example.net but have %s", cert.Subject.Organization[0])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Info("Overrode subject info")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOverwriteHosts(t *testing.T) {
 | 
			
		||||
	csrPEM, err := ioutil.ReadFile(testCSR)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile)
 | 
			
		||||
 | 
			
		||||
	request := signer.SignRequest{
 | 
			
		||||
		Hosts:   []string{"127.0.0.1", "localhost"},
 | 
			
		||||
		Request: string(csrPEM),
 | 
			
		||||
		Subject: nil,
 | 
			
		||||
	}
 | 
			
		||||
	certPEM, err := s.Sign(request)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, err := helpers.ParseCertificatePEM(certPEM)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("%v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get the hosts, and add the ips
 | 
			
		||||
	hosts, ips := cert.DNSNames, cert.IPAddresses
 | 
			
		||||
	for _, ip := range ips {
 | 
			
		||||
		hosts = append(hosts, ip.String())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// compare the sorted host lists
 | 
			
		||||
	sort.Strings(hosts)
 | 
			
		||||
	sort.Strings(request.Hosts)
 | 
			
		||||
	if !reflect.DeepEqual(hosts, request.Hosts) {
 | 
			
		||||
		t.Fatalf("Hosts not the same. cert hosts: %v, expected: %v", hosts, request.Hosts)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Info("Overwrote hosts")
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw
 | 
			
		||||
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
 | 
			
		||||
YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT
 | 
			
		||||
VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx
 | 
			
		||||
MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV
 | 
			
		||||
BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT
 | 
			
		||||
CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG
 | 
			
		||||
SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
 | 
			
		||||
MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4
 | 
			
		||||
BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d
 | 
			
		||||
hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt
 | 
			
		||||
HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw
 | 
			
		||||
aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN
 | 
			
		||||
8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3
 | 
			
		||||
0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p
 | 
			
		||||
/YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
 | 
			
		||||
aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx
 | 
			
		||||
GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz
 | 
			
		||||
dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq
 | 
			
		||||
hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3
 | 
			
		||||
F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc
 | 
			
		||||
depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet
 | 
			
		||||
Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv
 | 
			
		||||
qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd
 | 
			
		||||
H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ==
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
-----BEGIN PRIVATE KEY-----
 | 
			
		||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j
 | 
			
		||||
QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T
 | 
			
		||||
Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE
 | 
			
		||||
x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi
 | 
			
		||||
EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD
 | 
			
		||||
61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io
 | 
			
		||||
1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD
 | 
			
		||||
N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8
 | 
			
		||||
c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc
 | 
			
		||||
YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h
 | 
			
		||||
HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI
 | 
			
		||||
AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+
 | 
			
		||||
cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1
 | 
			
		||||
/2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P
 | 
			
		||||
kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt
 | 
			
		||||
hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz
 | 
			
		||||
cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/
 | 
			
		||||
uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E
 | 
			
		||||
wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p
 | 
			
		||||
PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq
 | 
			
		||||
4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk
 | 
			
		||||
s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27
 | 
			
		||||
ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43
 | 
			
		||||
rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi
 | 
			
		||||
0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV
 | 
			
		||||
xQB518/lp2eIeMpglWByDwJX
 | 
			
		||||
-----END PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										10
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256-inter.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										10
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256-inter.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIBezCCASECAQAwgYwxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMR0wGwYDVQQDExRjbG91ZGZsYXJl
 | 
			
		||||
LWludGVyLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgOKlWwIAIeURde
 | 
			
		||||
yvDMhgfn6xPp1gn8oUeLmsniBm7I+j84IsVzUso8/MpjMZ9nB8lQUanhv3Kmqcyj
 | 
			
		||||
HNj+iFegMjAwBgkqhkiG9w0BCQ4xIzAhMB8GA1UdEQQYMBaCFGNsb3VkZmxhcmUt
 | 
			
		||||
aW50ZXIuY29tMAoGCCqGSM49BAMCA0gAMEUCIEJcy2mn2YyK8lVE+HHmr2OsmdbH
 | 
			
		||||
4CLDVXFBwxke8ObqAiEAx/il1cDKvQ/I36b4XjBnOX2jcQ5oaCNPFFBE74WQ/ps=
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										5
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256-inter.key
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										5
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256-inter.key
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
-----BEGIN EC PRIVATE KEY-----
 | 
			
		||||
MHcCAQEEILbwI4u4bw+HtafMqFnrL7LOrqNEZH5rW5ygSrigfrVLoAoGCCqGSM49
 | 
			
		||||
AwEHoUQDQgAEuA4qVbAgAh5RF17K8MyGB+frE+nWCfyhR4uayeIGbsj6PzgixXNS
 | 
			
		||||
yjz8ymMxn2cHyVBRqeG/cqapzKMc2P6IVw==
 | 
			
		||||
-----END EC PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIBgTCCASgCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
 | 
			
		||||
LmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBn9Ldie6BOcMHezn2dPuYqW
 | 
			
		||||
z/NoLYMLGNBqhOxUyEidYClI0JW2pWyUgT3A2UazFp1WgE94y7Z+2YlfRz+vcrKg
 | 
			
		||||
PzA9BgkqhkiG9w0BCQ4xMDAuMCwGA1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3
 | 
			
		||||
d3djbG91ZGZsYXJlLmNvbTAKBggqhkjOPQQDAgNHADBEAiBM+QRxe8u6rkdr10Jy
 | 
			
		||||
cxbR6NxrGrNeg5QqiOqF96JEmgIgDbtjd5e3y3I8W/+ih2us3WtMxgnTXfqPd48i
 | 
			
		||||
VLcv28Q=
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										20
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256_ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										20
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256_ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIDUzCCAj2gAwIBAgIIbjeSyheUvjYwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQG
 | 
			
		||||
EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj
 | 
			
		||||
bzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVTVCBSb290
 | 
			
		||||
IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTQwNTI0MDQ1
 | 
			
		||||
MTQwWhcNMTUwNTI0MDQ1NjQwWjCBizELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNs
 | 
			
		||||
b3VkRmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcT
 | 
			
		||||
DVNhbiBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHDAaBgNVBAMTE2Ns
 | 
			
		||||
b3VkZmxhcmUtbGVhZi5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASMRv3x
 | 
			
		||||
vcv4I5QF7we+23hES2waKDffBRhQMVVAOSIJcpb4JnzcVJiPJjNlMPbczi5vbzkQ
 | 
			
		||||
K2kkjOP+okqQia3go4GGMIGDMA4GA1UdDwEB/wQEAwIABDAdBgNVHSUEFjAUBggr
 | 
			
		||||
BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQU
 | 
			
		||||
4t+cr91ma5IxOPeiezgN8W9FBNowHwYDVR0jBBgwFoAUt9L3hLqoOdX7rBDOKf2L
 | 
			
		||||
lqQT7L0wCwYJKoZIhvcNAQELA4IBAQAWloyDhrcYFSaZjzb8+UKxnukPUzd7BGaX
 | 
			
		||||
BvLktbN7hrX+z+ntA5UgXWo7uNgf2L3VwS0mVnRowwmrGV8Pbw9FX5WSisBQ+JJJ
 | 
			
		||||
JC4ABYT2N7N+B488zKZuMZY8NmSR/ples0Suz3oArUn4ZBGxANyOR6haBbYfupDF
 | 
			
		||||
LaCtAdQwZzNPfHAo2NsENSOlzGVhV0r1ZqalzkBf70K0KuAoLRbNG3Og17UeMb8K
 | 
			
		||||
5sXa7WvubgZ7/D3lr//F56yJYyfTq8SWcIi4e9AUWY5qK+Sr+7W9/gSY3baaHxY9
 | 
			
		||||
T9SO4O1ENFJ8ecWRPdsiBNCpl53qMuYW2lh72N35Iyug6qKFDYg5
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										5
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256_ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										5
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa256_ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
-----BEGIN EC PRIVATE KEY-----
 | 
			
		||||
MHcCAQEEIC2qaVydr67HuwWMrPQ3ljCVSsnbV7HbN78KqEX6a0GuoAoGCCqGSM49
 | 
			
		||||
AwEHoUQDQgAEjEb98b3L+COUBe8Hvtt4REtsGig33wUYUDFVQDkiCXKW+CZ83FSY
 | 
			
		||||
jyYzZTD23M4ub285ECtpJIzj/qJKkImt4A==
 | 
			
		||||
-----END EC PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										12
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa384.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										12
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa384.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIBvzCCAUUCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
 | 
			
		||||
LmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBk/Q+zMsZOJGkufRzGCWtSUtRjq
 | 
			
		||||
0QqChDGWbHLaa0h6ODVeEoKYOMvFJTg4V186tuuBe97KEey0OPDegzCBp5kBIiwg
 | 
			
		||||
HB/0xWoKdnfdRk6VyjmubPx399cGoZn8aCqgC6A/MD0GCSqGSIb3DQEJDjEwMC4w
 | 
			
		||||
LAYDVR0RBCUwI4IOY2xvdWRmbGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAoG
 | 
			
		||||
CCqGSM49BAMDA2gAMGUCMQC57VfwMXDyL5kM7vmO2ynbpgSAuFZT6Yd3C3NnV2jz
 | 
			
		||||
Biozw3eqIDXqCb2LI09stZMCMGIwCuVARr2IRctxf7AmX7/O2SIaIhCpMFKRedQ7
 | 
			
		||||
RiWGZIucp5r6AfT9381PB29bHA==
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa521.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										13
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ecdsa521.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIICCjCCAWsCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
 | 
			
		||||
LmNvbTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAHt/s9KTZETzu94JIAjZ3BaS
 | 
			
		||||
toSG65hGIc1e0Gt7PhdQxPp5FP2D8rQ1wc+pcZhD2O8525kPxopaqTd+fWKBuD3O
 | 
			
		||||
AULzoH2OX+atIuumTQzLNbTsIbP0tY3dh7d8LItuERkZn1NfsNl3z6bnNAaR137m
 | 
			
		||||
f4aWv49ImbA/Tkv8VmoKX279oD8wPQYJKoZIhvcNAQkOMTAwLjAsBgNVHREEJTAj
 | 
			
		||||
gg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xvdWRmbGFyZS5jb20wCgYIKoZIzj0EAwQD
 | 
			
		||||
gYwAMIGIAkIA8OX9LxWOVnyfB25DFBz6JkjhyDpBM/PXlgLnWb/n2mEuMMB44DOG
 | 
			
		||||
pljDV768PSW11AC3DtULoIyR92z0TyLEKYoCQgHdGd6PwUtDW5mrAMJQDgebjsxu
 | 
			
		||||
MwfcdthzKlFlSmRpHMBnRMOJjlg5f9CTBg9d6wEdv7ZIrQSO6eqQHDQRM0VMnw==
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ex.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ex.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIBnzCCAQgCAQAwXzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMQ8wDQYDVQQH
 | 
			
		||||
DAZJdGhhY2ExHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxFDASBgNVBAMM
 | 
			
		||||
C2V4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBPmzv1c1e
 | 
			
		||||
QAa1yTtJ45oPOCARrhqDYV66urzNX1zHDZzi4lruIfI3q+1McACs4FIGJAkBUC2O
 | 
			
		||||
ZCamsR6ym5PaL9+dGfgVvf6w/GoBb65bxuw/IgHnzhfEHsk9nV8WthTEHmT9m9lh
 | 
			
		||||
kPMZBVDIVFW6iOCCpAwR6I9XXB30oKTINwIDAQABoAAwDQYJKoZIhvcNAQELBQAD
 | 
			
		||||
gYEAndd8OjJ+Jr74jqwuV9cUDqlItsLc84TYn+lly0EPezGQIIYz2KUoDyHQ+PQ9
 | 
			
		||||
7JI3G3FWR8Wpow7HooLJRxHNWOw7u8ekLCP0LjkoHse+Dou5C0jzo99jfrjXNWGt
 | 
			
		||||
DZO0Wrpu2eDclqwMJO/DtiovzcmOsGC52NHUW6+Moo9N2lM=
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ip.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										11
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/ip.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIBlTCB/wIBADBWMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTlkxDzANBgNVBAcM
 | 
			
		||||
Bkl0aGFjYTEQMA4GA1UECgwHQ29ybmVsbDEXMBUGA1UEAwwOMTI4Ljg0LjEyNi4y
 | 
			
		||||
MTMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAME+bO/VzV5ABrXJO0njmg84
 | 
			
		||||
IBGuGoNhXrq6vM1fXMcNnOLiWu4h8jer7UxwAKzgUgYkCQFQLY5kJqaxHrKbk9ov
 | 
			
		||||
350Z+BW9/rD8agFvrlvG7D8iAefOF8QeyT2dXxa2FMQeZP2b2WGQ8xkFUMhUVbqI
 | 
			
		||||
4IKkDBHoj1dcHfSgpMg3AgMBAAGgADANBgkqhkiG9w0BAQsFAAOBgQBS7FBieNEN
 | 
			
		||||
PfXQRhPeiZ86QatshBBrj+TmhdC4GjtJ9lQA2NSRg2HnSHDErxdezZ7tw1ordd5D
 | 
			
		||||
hZpJ8XkPggsb7mghwPD7Zzgp0M/ldqbZ9fFEtNcpiEL05vKtap5uSGzNn32NDbQa
 | 
			
		||||
g+4QnDavffTQuzfuOoGJ9bG3jQtxo9HZCA==
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										15
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										15
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIICXAIBAAKBgQCbp/6OQ/a3mr+8zRgBRlmSGr8QBgP4vUIxLn2Mk4uiZ8OcpRY4
 | 
			
		||||
YqL+TtREGDUc0ve+bv8RINrNlYXL2X+eJtbE2RJQ+RAiu+saw2K+RFTNeTCA1fwg
 | 
			
		||||
3ws5gBDcFbECqK1dOkuN/gV4JMHobn2/15iUBfeSJxdF1j5yqES8sVu7cwIDAQAB
 | 
			
		||||
AoGBALZOnnBV3aLRlnw04kar9MCQnvLPeNteHyanQtjg/oxqZ8sR9+J2dFzSSv6u
 | 
			
		||||
M5bc6Nmb+xY+msZqt9g3l6bN6n+qCvNnLauIY/YPjd577uMTpx/QTOQSK8oc5Dhi
 | 
			
		||||
WgdU8GCtUmY+LE8qYx2NFitKCN4hubdrI76c+rnezIPVncZRAkEA9T5+vlfwk/Zl
 | 
			
		||||
DOte+JtbXx3RtXKFJPMirOFqNVp1qnIlUm8XtBW6760ugiNYbVbGHgbd8JsZnkPH
 | 
			
		||||
NC17TNLVJwJBAKJ7pDlJ2mvVr0cLrFhjAibz45dOipt8B4+dKtDIEuqbtKzJCGuP
 | 
			
		||||
SCk4X2SgYz0gC5kH62S7rn6Bsa9lM98dztUCQASdLWNFYkhWXWZV006YFar/c5+X
 | 
			
		||||
TPv5+xAHmajxT79qMFuRrX983Sx/NJ3MLnC4LjgIZwqM0HmSyt+nb2dtnAcCQCKi
 | 
			
		||||
nIUhuw+Vg0FvuZM1t7W581/DfERckfgJFqFepLmh60eRqtvStR0kSSFYFw9mj1JV
 | 
			
		||||
n9XfM/j/iHLM7du3rOkCQAw9R64yjcIBwcoSQxW/dr0Q9j+SnYgt+EhyXYXT30DS
 | 
			
		||||
DdOJ06GXtb/P0peFBp26BnQU4CSS75yseZ1TdB4ZqaA=
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										19
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa2048-inter.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										19
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa2048-inter.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIDCjCCAfQCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
 | 
			
		||||
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOLFLykOd2j31AQn
 | 
			
		||||
kaToYtstGvw5wLb4YnlzipQ6aULlD0H0GHM9IwhdSmcTWUWPb/U83g/ma1uD3Pp2
 | 
			
		||||
IdWd6xfjyOJF5XhgkyfRY65wS6vPZRm2MNSFXem+0AKHdhxIhb/QPMASqC/yaiPi
 | 
			
		||||
nvtOpBiCNl1Q2N4y9pkV0oD/T4rrn3RXP6iL1k4CNRS54JPCd+aI5Om+axVPU8Id
 | 
			
		||||
ZeUXQwXISaFrcC/bFXAHGX5hBMVu34lhCxvR4smweZkVmW++bIv26az8TSb5nVn4
 | 
			
		||||
TstLJIaOoOqot0sis04+0oX/GXfTPfkWyzfTVFN7cb9H+gz0FZJKtXQZv6qdntji
 | 
			
		||||
9FdR+pkCAwEAAaBAMD4GCSqGSIb3DQEJDjExMC8wLQYDVR0RBCYwJIIOY2xvdWRm
 | 
			
		||||
bGFyZS5jb22CEnd3dy5jbG91ZGZsYXJlLmNvbTALBgkqhkiG9w0BAQsDggEBABfM
 | 
			
		||||
9XTMqMqmfAAymWC4/W+vbh301KBoydcTnDQ/7B+ftHRE0O3FUsdL3wobj3qBieJo
 | 
			
		||||
MiQwiL7+GksszHvN9+YOUi70wpFuKghLhadb7p5GzL0+JgK2eQnLYb37/lQSiWwn
 | 
			
		||||
hht1YMOzErR/KHlxNUafk71bDEeytUcOvvtujf86nZiEnBpvp47zDjMkDersczM0
 | 
			
		||||
wj7S50IY8/vRsc2Q8vy+Q7D2FPEwjs4wCGVSqzwX2NPn3fZb/2pWRCie9kxHUfUP
 | 
			
		||||
L5xO4WoFGuirT6E2GnUWDdH661Pj5yEKvmr+qPl+eVoLjrtx0g5rAmA7rGlGrkqp
 | 
			
		||||
r4idH/BbJUaDlRHM/Hk=
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa2048-inter.key
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa2048-inter.key
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEpQIBAAKCAQEA4sUvKQ53aPfUBCeRpOhi2y0a/DnAtvhieXOKlDppQuUPQfQY
 | 
			
		||||
cz0jCF1KZxNZRY9v9TzeD+ZrW4Pc+nYh1Z3rF+PI4kXleGCTJ9FjrnBLq89lGbYw
 | 
			
		||||
1IVd6b7QAod2HEiFv9A8wBKoL/JqI+Ke+06kGII2XVDY3jL2mRXSgP9PiuufdFc/
 | 
			
		||||
qIvWTgI1FLngk8J35ojk6b5rFU9Twh1l5RdDBchJoWtwL9sVcAcZfmEExW7fiWEL
 | 
			
		||||
G9HiybB5mRWZb75si/bprPxNJvmdWfhOy0skho6g6qi3SyKzTj7Shf8Zd9M9+RbL
 | 
			
		||||
N9NUU3txv0f6DPQVkkq1dBm/qp2e2OL0V1H6mQIDAQABAoIBAQCzT3HcCAlZoeUu
 | 
			
		||||
p88dU3efkUnuOQhuZXcQS9E/JfTHpXHsF8Qhky0ZVxMW8BC91Q6VHt0EO5GWWm0o
 | 
			
		||||
SrK0Q9t6F25npRcumUaizIoCi9756tMpgouX8CDzTCMUbOJyuNGxe0oeImKFDyzo
 | 
			
		||||
VTCazHMqwgOUw/HHuQqOv9ekkrzlva8U+Z5MGZB4B2acHIAJHO9uYGzdeAjF3grm
 | 
			
		||||
dQ3QFGXJM0JzPmXfnUiDeOWIoVbo4YROFhf7qNlcnyLdkrYe0/XsSYQM9dRGKRPK
 | 
			
		||||
nkOkMv0sC8rOqNuJUn3tf1OOjzVQxlzB8Key6MOQ1c+kqsdCnL88/93CvI5NHazx
 | 
			
		||||
hwUmesmBAoGBAPpkDtgeWjxeIjOfuxXDYb04XbVmKquKNOIEk5OADmaacSGzdemh
 | 
			
		||||
XLRaNVMEYMcgMJViDDKW8g4k+zuZgzooMxNynlLNU5wfazwX2LLjReJFvZb/SxMM
 | 
			
		||||
N9+vQo8fcGz+p5g1tbeE6w86mpsTiAGx9Wa4J4GnY8jF6XUjZHO0X91pAoGBAOfZ
 | 
			
		||||
qrDkPMDSiVk62FP6LlPrj09bt1NTkBfv5dWhN/XeHjuus7unDhNiRmphhgF0VZse
 | 
			
		||||
XPtT/PUO0YgYlyaYJDDDE0IxgHuoK9wvEb2sqEtkZSw7IUhehheZ/+YfXzSA5fwa
 | 
			
		||||
vhXt0ghB0d9oVJuRoxb17MncjpjDAKy0QR5drR2xAoGBAMlNwkVseZ2JDLQ2WgHQ
 | 
			
		||||
N/cZpvUc83dAQO3pQgBW9rz0s7mlf0naqh5xW+enYGsW7RhcYHQXuPk4MCelbsRF
 | 
			
		||||
53JeNv1ZCDw/YkZI4bZIVDnrWdZY3zGsJAuY6skIPKnUPkd3/uVRXm267ut4U2MR
 | 
			
		||||
gLsZmOF7AxU6UEwVrT/8pwnpAoGAKxbVFlMUx3FZfW/mTJUujwI0fDc7dw0MtqYr
 | 
			
		||||
POzdjaBeVhE97h46C3g0Rgkh8ptAXbfi6ALP/GtonbaUQOP9teJLbf3tNw4mOKG2
 | 
			
		||||
1l2EWZ6q/vFuWhjXKwO//3DNLODX3WbK9SBh7I7vBmpJbzA980J5Y3rONa3oLjDB
 | 
			
		||||
+XbHecECgYEArOEv2D3fE3Hd6rEbxXinqekxMa+V1OCDO1IPz4wwr9RDMVUMxwqF
 | 
			
		||||
f0es1PQ2eMJGrAMbySxPfSZG05ou/tA+zR0qPwc/+dX0BbaXCiNT3gbhvL1L2fBc
 | 
			
		||||
7wr+MIUe2fi54JUWrUNMDHngRhXRKt2rZZRTfqVaFmZX02Y3fMZ2dWg=
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										19
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa2048.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										19
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa2048.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIDCTCCAfMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
 | 
			
		||||
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTWdoYxX4KN51fP
 | 
			
		||||
WxQAyGH++VsPbfpAoXIbCPXSmU04BvIxyjzpHQ0ChMKkT/2VNcUeFJwk2fCf+ZwU
 | 
			
		||||
f0raTQTplofwkckE0gEYA3WcEfJp+hbvbTb/2recsf+JE6JACYJe2Uu5wsjtrE5j
 | 
			
		||||
A+7aT2BEU9RWzBdSy/5281ZfW3PArqcWaf8+RUyA3WRxVWmjmhFsVB+mdNLhCpW0
 | 
			
		||||
C0QNMYR1ppEZiKVnEdao8gcI5sOvSd+35t8g82aPXcNSPU6jKcx1YNUPX5wgPEmu
 | 
			
		||||
+anfc9RliQbYqqJYVODgBmV8IR5grw93yTsODoWKtFQ4PKVlnt9CD8AS/iSMQYm3
 | 
			
		||||
OUogqgMCAwEAAaA/MD0GCSqGSIb3DQEJDjEwMC4wLAYDVR0RBCUwI4IOY2xvdWRm
 | 
			
		||||
bGFyZS5jb22CEXd3d2Nsb3VkZmxhcmUuY29tMAsGCSqGSIb3DQEBCwOCAQEAl809
 | 
			
		||||
gk9uZkRK+MJVYDSLjgGR2xqk5qOwnhovnispA7N3Z1GshodJRQa6ngNCKuXIm2/6
 | 
			
		||||
AxB9kDGK14n186Qq4odXqHSHs8FG9i0zUcBXeLv1rPAKtwKTas/SLmsOpPgWPZFa
 | 
			
		||||
iYiHHeu4HjOQoF987d7uGRYwc3xfstKwJsEXc12eCw2NH8TM1tJgSc/o6CzIpA91
 | 
			
		||||
QnZKhx6uGM4xI2gnOaJA1YikNhyFGBuOGMZgd0k2+/IcR2pg0z4pc5oQw1bXLANx
 | 
			
		||||
anqlA/MDrCM9v9019bRJ73zK8LQ3k/FW61PA9nL7RZ8ku65R+uYcVEdLa8pUeqnH
 | 
			
		||||
cJZNboDRsItpccZuRQ==
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										24
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa3072.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										24
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa3072.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIECTCCAnMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
 | 
			
		||||
LmNvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAL0zzgBv+VTwZOPy
 | 
			
		||||
LtuLFweQrj5Lfrje2hnNB7Y3TD4+yCM/cA4yTILixCe/B+N7LQysJgVDbW8u6BZQ
 | 
			
		||||
8ZqeDKOP6KCt37WhmcbT45tLpHmH+Z/uAnCz0hVc/7AyJ3CJXo6PaDCcJjgLuUun
 | 
			
		||||
W47iy4h79AxyuzELmUeZZGYcO8nqClqcnAzQ6sClGZvJwSbYg2QAFGoA2lHqZ9uN
 | 
			
		||||
ygAxNLd+rX9cP+yFwAeKzuKtOnVPiJD5lT3wufSkAbd6M7lOoqmTYnbv0A1WfA/e
 | 
			
		||||
upXno9lbgB6iwF5U0V7OtxdA1bTbvgJgNLlxFF1do0sB28CWmqCFNwLfzcPzt5A4
 | 
			
		||||
gLnOyLhNZOmUMXn35KOtp1Zv/yethlgZHxUYGcl6OYwMEFye3Du6dgnTwONzaLhA
 | 
			
		||||
7hMI8R60p2YrTLkgSKdFohAY/mKuxHyXxugOHHthlRCOn9m49edcdZ1HrkJXm9jd
 | 
			
		||||
P9katjCXgTwSdTQlvaMJkfH7wF3ZMjAxPcDf4RKFEpF2wABeNQIDAQABoD8wPQYJ
 | 
			
		||||
KoZIhvcNAQkOMTAwLjAsBgNVHREEJTAjgg5jbG91ZGZsYXJlLmNvbYIRd3d3Y2xv
 | 
			
		||||
dWRmbGFyZS5jb20wCwYJKoZIhvcNAQEMA4IBgQBF/RCHNAAOAaRI4VyO0tRPA5Dw
 | 
			
		||||
0/1/pgmBm/VejHIwDJnMFCl9njh0RSo1RgsVLhw6ovYbk3ORb4OD4UczPTq3GrFp
 | 
			
		||||
KP9uPR+2pR4FWJpCVfCl76YabQv6fUDdiT7ojzyRhsAmkd5rOdiMvWV3Rp+YmBuU
 | 
			
		||||
KH/dwkukfn+OeJIbERS5unzOBtQL+g5dU4CHWAqJQIqHr373w38OlYN+JY9QLrYy
 | 
			
		||||
sWU9Ye6RjdySXPJ5UzyfOEfc9Ji89RJsVeceB1+As5u5vBvtzGgIMSFUzN947RZo
 | 
			
		||||
DZ48JiB71VpmKXbn9LIRn25dlbVMzxRdSeZ194L3JFVAf9OxJTsc1QNFhOacoFgy
 | 
			
		||||
hqvtN2iKntEyPo2nacYhpz/FAdJ2JThNH+4WtpPWAqx8Lw/e1OttiDt+6M0FEuVz
 | 
			
		||||
svkSHnK206yo+a9Md37nUDDYxtlJEB+9F2qUZNQ7Hv+dxjmJOIgHOXxy1pLEdpVU
 | 
			
		||||
rGdGLVXeJNPCh9x+GK21QjdxZABmYAaF8k36Pv4=
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										29
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa4096.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										29
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local/testdata/rsa4096.csr
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
-----BEGIN CERTIFICATE REQUEST-----
 | 
			
		||||
MIIFCTCCAvMCAQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpDbG91ZEZsYXJl
 | 
			
		||||
MRwwGgYDVQQLExNTeXN0ZW1zIEVuZ2luZWVyaW5nMRYwFAYDVQQHEw1TYW4gRnJh
 | 
			
		||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRcwFQYDVQQDEw5jbG91ZGZsYXJl
 | 
			
		||||
LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANkKL22jMn3eFCpj
 | 
			
		||||
T6lbeq4nC3aEqwTGrLARidAmO29WIhzs6LxRpM6xSMoPI6DvJVUGpMFEKF4xNTc5
 | 
			
		||||
X9/gSFrw2eI5Q3U3aGcaToSCxH4hXejwIzX8Ftlb/LfpXhbSsFr5MS3kiTY4zZxM
 | 
			
		||||
n3dSy2gZljD/g0tlQf5BdHdR4WKRhWnqRiGng+BmW4rjbcO7SoN33jSXsMcguCg5
 | 
			
		||||
8dmYuf5G5KVXsqwEoCQBeKGnca9orcm4i90VnGt4qZUpfAn1cADzYGpRzX79USJ6
 | 
			
		||||
tol4ovgGPN08LJFqcVl+dK8VzJ03JWBhI1jePbWS4Bz5oNtkhQQXilU+G6FQxc6a
 | 
			
		||||
UPf6KcFyOB+qMJmEwJZD9yaNK1YbsKfSztQEsb1JEezQnVHxp91Ch3AcWoikuOiY
 | 
			
		||||
yCg0V5lcK15SLv1+5sj9YzF7ngMmThcIJ6B5gS3swpD5AX6FJaI1BrGwT/RXKKQP
 | 
			
		||||
tRX1BySLx8RcINjFb5wv3q9QIE8vrW1BOk9f4dfmxiFYnc+6bCCbIrg7APQVtKTa
 | 
			
		||||
ixNJFSqZz7fm9loeNPHHXfUT5RoW5yzVa8igc+yv4qeYsWHcZ4c/Y91OJp19HMjM
 | 
			
		||||
bYm2alt8XagBgJjO0FW8wvsKwhhlhWK0WO6sQ7Fkl7fH1GtxEpc248hAW24SZMmS
 | 
			
		||||
led3LblCT8IC3a9BLhqJ2q8cfPp9AgMBAAGgPzA9BgkqhkiG9w0BCQ4xMDAuMCwG
 | 
			
		||||
A1UdEQQlMCOCDmNsb3VkZmxhcmUuY29tghF3d3djbG91ZGZsYXJlLmNvbTALBgkq
 | 
			
		||||
hkiG9w0BAQ0DggIBAAgz3NuN43+F+8+WhQ9hb7DOp6Amut7XubOkEBtBVgP3R8U1
 | 
			
		||||
uSsgocR1rvnZ1/bhkeGyTly0eQPhcSEdMo/GgIrcn+co0KLcDyV6Rf3Cgksx9dUZ
 | 
			
		||||
TzHSkxmFkxlxYfIGes6abH+2OPiacwK2gLvvmXFYIxEhv+LKzzteQi0xlinewv7R
 | 
			
		||||
FnSykZ4QialsFyCgOjOxa11aEdRv6T8qKwhjUOk0VedtzOkt/k95aydTNLjXl2OV
 | 
			
		||||
jloeTsbB00yWIqdyhG12+TgcJOa0pNP1zTjgFPodMuRUuiAcbT7Mt7sLCefKNzvZ
 | 
			
		||||
Ln6b4y7e6N3YLOHALTIP+LI4y8ar47WlXCNw/zeOM2sW8udjYrukN6WOV3X68oMf
 | 
			
		||||
Zsv6jqyGSaCDwdImR4VECUVvkabg9Sq4pz+ijTT+9cNA66omYL+/QAh0GahlROgW
 | 
			
		||||
kDGI8zeEUoAC8RkAbFGMJA8jEbAfbT000ZwnLX2SZ8YRQX4Jd1FTmAH99FkvvT8N
 | 
			
		||||
ovaGRSQQI5rWQGQYqF67So7PywEaEXeUHTBrv41Msva6CdaWHn7bh/fj4B21ETS7
 | 
			
		||||
VJvrk5DLJTyruqon7EVJU1pn38ppaXF4Z6a9n3C8TqudT/gdJUYn/SBo5jx20uGJ
 | 
			
		||||
d9k6vDqixntvk/TRZ848k1AXiv5uUJTdnoPPhzSGjxEaeKuB0R1ZHomVdjU4
 | 
			
		||||
-----END CERTIFICATE REQUEST-----
 | 
			
		||||
							
								
								
									
										4
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11/doc.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										4
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11/doc.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
// Package pkcs11 implements support for PKCS #11 signers. If the
 | 
			
		||||
// package has not been built with the `pkcs11` tag, the `New`
 | 
			
		||||
// function will be a stub.
 | 
			
		||||
package pkcs11
 | 
			
		||||
							
								
								
									
										53
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11/pkcs11.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										53
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11/pkcs11.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
// +build pkcs11
 | 
			
		||||
 | 
			
		||||
package pkcs11
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
 | 
			
		||||
	"github.com/cloudflare/cfssl/crypto/pkcs11key"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config contains configuration information required to use a PKCS
 | 
			
		||||
// #11 key.
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Module string
 | 
			
		||||
	Token  string
 | 
			
		||||
	PIN    string
 | 
			
		||||
	Label  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Enabled is set to true if PKCS #11 support is present.
 | 
			
		||||
const Enabled = true
 | 
			
		||||
 | 
			
		||||
// New returns a new PKCS #11 signer.
 | 
			
		||||
func New(caCertFile string, policy *config.Signing, cfg *Config) (signer.Signer, error) {
 | 
			
		||||
	if cfg == nil {
 | 
			
		||||
		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Debugf("Loading PKCS #11 module %s", cfg.Module)
 | 
			
		||||
	certData, err := ioutil.ReadFile(caCertFile)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, err := helpers.ParseCertificatePEM(certData)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priv, err := pkcs11key.New(cfg.Module, cfg.Token, cfg.PIN, cfg.Label)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed)
 | 
			
		||||
	}
 | 
			
		||||
	sigAlgo := signer.DefaultSigAlgo(priv)
 | 
			
		||||
 | 
			
		||||
	return local.NewSigner(priv, cert, sigAlgo, policy)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11/pkcs11_stub.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/pkcs11/pkcs11_stub.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
// +build !pkcs11
 | 
			
		||||
 | 
			
		||||
package pkcs11
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Config contains configuration information required to use a PKCS
 | 
			
		||||
// #11 key.
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Module string
 | 
			
		||||
	Token  string
 | 
			
		||||
	PIN    string
 | 
			
		||||
	Label  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New always returns an error. If PKCS #11 support is needed, the
 | 
			
		||||
// program should be built with the `pkcs11` build tag.
 | 
			
		||||
func New(caCertFile string, policy *config.Signing, cfg *Config) (signer.Signer, error) {
 | 
			
		||||
	return nil, errors.New(errors.PrivateKeyError, errors.Unknown)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Enabled is set to true if PKCS #11 support is present.
 | 
			
		||||
const Enabled = false
 | 
			
		||||
							
								
								
									
										114
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/remote.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										114
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/remote.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
package remote
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Signer represents a CFSSL instance running as signing server.
 | 
			
		||||
// fulfills the signer.Signer interface
 | 
			
		||||
type Signer struct {
 | 
			
		||||
	policy *config.Signing
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSigner creates a new remote Signer directly from a
 | 
			
		||||
// signing policy.
 | 
			
		||||
func NewSigner(policy *config.Signing) (*Signer, error) {
 | 
			
		||||
	if policy != nil {
 | 
			
		||||
		if !policy.Valid() {
 | 
			
		||||
			return nil, cferr.New(cferr.PolicyError,
 | 
			
		||||
				cferr.InvalidPolicy)
 | 
			
		||||
		}
 | 
			
		||||
		return &Signer{policy: policy}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, cferr.New(cferr.PolicyError,
 | 
			
		||||
		cferr.InvalidPolicy)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sign sends a signature request to the remote CFSSL server,
 | 
			
		||||
// receiving a signed certificate or an error in response. The hostname,
 | 
			
		||||
// csr, and profileName are used as with a local signing operation, and
 | 
			
		||||
// the label is used to select a signing root in a multi-root CA.
 | 
			
		||||
func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 | 
			
		||||
	return s.remoteOp(req, req.Profile, "sign")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Info sends an info request to the remote CFSSL server, receiving a signed
 | 
			
		||||
// certificate or an error in response.
 | 
			
		||||
func (s *Signer) Info(req client.InfoReq) (cert []byte, err error) {
 | 
			
		||||
	return s.remoteOp(req, req.Profile, "info")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper function to perform a remote sign or info request.
 | 
			
		||||
func (s *Signer) remoteOp(req interface{}, profile, target string) (cert []byte, err error) {
 | 
			
		||||
	jsonData, err := json.Marshal(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.APIClientError, cferr.JSONError, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var p *config.SigningProfile
 | 
			
		||||
	if s.policy.Profiles != nil && profile != "" {
 | 
			
		||||
		p = s.policy.Profiles[profile]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p == nil {
 | 
			
		||||
		p = s.policy.Default
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server := client.NewServer(p.RemoteServer)
 | 
			
		||||
	if server == nil {
 | 
			
		||||
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest,
 | 
			
		||||
			errors.New("failed to connect to remote"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// There's no server-side auth provider for the "info" method
 | 
			
		||||
	// TODO: Revert this change once there is an AuthInfo provider.
 | 
			
		||||
	if p.Provider != nil && target != "info" {
 | 
			
		||||
		cert, err = server.AuthReq(jsonData, nil, p.Provider, target)
 | 
			
		||||
	} else {
 | 
			
		||||
		cert, err = server.Req(jsonData, target)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return []byte(cert), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SigAlgo returns the RSA signer's signature algorithm.
 | 
			
		||||
func (s *Signer) SigAlgo() x509.SignatureAlgorithm {
 | 
			
		||||
	// TODO: implement this as a remote info call
 | 
			
		||||
	return x509.UnknownSignatureAlgorithm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Certificate returns the signer's certificate.
 | 
			
		||||
func (s *Signer) Certificate(label, profile string) (*x509.Certificate, error) {
 | 
			
		||||
	certStr, err := s.Info(client.InfoReq{Label: label, Profile: profile})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	cert, err := helpers.ParseCertificatePEM(certStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return cert, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetPolicy sets the signer's signature policy.
 | 
			
		||||
func (s *Signer) SetPolicy(policy *config.Signing) {
 | 
			
		||||
	s.policy = policy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Policy returns the signer's policy.
 | 
			
		||||
func (s *Signer) Policy() *config.Signing {
 | 
			
		||||
	return s.policy
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										399
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/remote_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										399
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/remote_test.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,399 @@
 | 
			
		|||
package remote
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/http/httptest"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api/client"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/api/info"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/log"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/local"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	testCaFile    = "testdata/ca.pem"
 | 
			
		||||
	testCaKeyFile = "testdata/ca_key.pem"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var validMinimalRemoteConfig = `
 | 
			
		||||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"default": {
 | 
			
		||||
			"remote": "localhost"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:80"
 | 
			
		||||
	}
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
var validMinimalAuthRemoteConfig = `
 | 
			
		||||
{
 | 
			
		||||
	"signing": {
 | 
			
		||||
		"default": {
 | 
			
		||||
			"auth_key": "sample",
 | 
			
		||||
			"remote": "localhost"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"auth_keys": {
 | 
			
		||||
		"sample": {
 | 
			
		||||
			"type":"standard",
 | 
			
		||||
			"key":"0123456789ABCDEF0123456789ABCDEF"
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	"remotes": {
 | 
			
		||||
		"localhost": "127.0.0.1:80"
 | 
			
		||||
	}
 | 
			
		||||
}`
 | 
			
		||||
 | 
			
		||||
func TestNewSigner(t *testing.T) {
 | 
			
		||||
	remoteConfig := newConfig(t, []byte(validMinimalRemoteConfig))
 | 
			
		||||
 | 
			
		||||
	_, err := NewSigner(remoteConfig.Signing)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("fail to init remote signer:", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNewAuthSigner(t *testing.T) {
 | 
			
		||||
	remoteAuthConfig := newConfig(t, []byte(validMinimalAuthRemoteConfig))
 | 
			
		||||
 | 
			
		||||
	_, err := NewSigner(remoteAuthConfig.Signing)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("fail to init remote signer:", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemoteInfo(t *testing.T) {
 | 
			
		||||
	remoteServer := newTestInfoServer(t)
 | 
			
		||||
	defer closeTestServer(t, remoteServer)
 | 
			
		||||
 | 
			
		||||
	remoteConfig := newConfig(t, []byte(validMinimalRemoteConfig))
 | 
			
		||||
	// override with test server address, ignore url prefix "http://"
 | 
			
		||||
	remoteConfig.Signing.OverrideRemotes(remoteServer.URL[7:])
 | 
			
		||||
	s := newRemoteSigner(t, remoteConfig.Signing)
 | 
			
		||||
	req := client.InfoReq{}
 | 
			
		||||
	certBytes, err := s.Info(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("remote info failed:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	caBytes, err := ioutil.ReadFile(testCaFile)
 | 
			
		||||
	caBytes = bytes.TrimSpace(caBytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("fail to read test CA cert:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if bytes.Compare(caBytes, certBytes) != 0 {
 | 
			
		||||
		t.Fatal("Get a different CA cert through info api.", len(certBytes), len(caBytes))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type csrTest struct {
 | 
			
		||||
	file    string
 | 
			
		||||
	keyAlgo string
 | 
			
		||||
	keyLen  int
 | 
			
		||||
	// Error checking function
 | 
			
		||||
	errorCallback func(*testing.T, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var csrTests = []csrTest{
 | 
			
		||||
	{
 | 
			
		||||
		file:          "../local/testdata/rsa2048.csr",
 | 
			
		||||
		keyAlgo:       "rsa",
 | 
			
		||||
		keyLen:        2048,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "../local/testdata/rsa3072.csr",
 | 
			
		||||
		keyAlgo:       "rsa",
 | 
			
		||||
		keyLen:        3072,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "../local/testdata/rsa4096.csr",
 | 
			
		||||
		keyAlgo:       "rsa",
 | 
			
		||||
		keyLen:        4096,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "../local/testdata/ecdsa256.csr",
 | 
			
		||||
		keyAlgo:       "ecdsa",
 | 
			
		||||
		keyLen:        256,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "../local/testdata/ecdsa384.csr",
 | 
			
		||||
		keyAlgo:       "ecdsa",
 | 
			
		||||
		keyLen:        384,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		file:          "../local/testdata/ecdsa521.csr",
 | 
			
		||||
		keyAlgo:       "ecdsa",
 | 
			
		||||
		keyLen:        521,
 | 
			
		||||
		errorCallback: nil,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemoteSign(t *testing.T) {
 | 
			
		||||
	remoteServer := newTestSignServer(t)
 | 
			
		||||
	defer closeTestServer(t, remoteServer)
 | 
			
		||||
 | 
			
		||||
	remoteConfig := newConfig(t, []byte(validMinimalRemoteConfig))
 | 
			
		||||
	// override with test server address, ignore url prefix "http://"
 | 
			
		||||
	remoteConfig.Signing.OverrideRemotes(remoteServer.URL[7:])
 | 
			
		||||
	s := newRemoteSigner(t, remoteConfig.Signing)
 | 
			
		||||
 | 
			
		||||
	hosts := []string{"cloudflare.com"}
 | 
			
		||||
	for _, test := range csrTests {
 | 
			
		||||
		csr, err := ioutil.ReadFile(test.file)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal("CSR loading error:", err)
 | 
			
		||||
		}
 | 
			
		||||
		certBytes, err := s.Sign(signer.SignRequest{Hosts: hosts, Request: string(csr)})
 | 
			
		||||
		if test.errorCallback != nil {
 | 
			
		||||
			test.errorCallback(t, err)
 | 
			
		||||
		} else {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen)
 | 
			
		||||
			}
 | 
			
		||||
			_, err := helpers.ParseCertificatePEM(certBytes)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				t.Fatal("Fail to parse returned certificate:", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRemoteSignBadServerAndOverride(t *testing.T) {
 | 
			
		||||
	remoteServer := newTestSignServer(t)
 | 
			
		||||
	defer closeTestServer(t, remoteServer)
 | 
			
		||||
 | 
			
		||||
	// remoteConfig contains port 80 that no test server will listen on
 | 
			
		||||
	remoteConfig := newConfig(t, []byte(validMinimalRemoteConfig))
 | 
			
		||||
	s := newRemoteSigner(t, remoteConfig.Signing)
 | 
			
		||||
 | 
			
		||||
	hosts := []string{"cloudflare.com"}
 | 
			
		||||
	csr, err := ioutil.ReadFile("../local/testdata/rsa2048.csr")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("CSR loading error:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = s.Sign(signer.SignRequest{Hosts: hosts, Request: string(csr)})
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Should return error")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	remoteConfig.Signing.OverrideRemotes(remoteServer.URL[7:])
 | 
			
		||||
	s.SetPolicy(remoteConfig.Signing)
 | 
			
		||||
	certBytes, err := s.Sign(signer.SignRequest{Hosts: hosts, Request: string(csr)})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Expected no error. Got %s.", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	_, err = helpers.ParseCertificatePEM(certBytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("Fail to parse returned certificate:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// helper functions
 | 
			
		||||
func newConfig(t *testing.T, configBytes []byte) *config.Config {
 | 
			
		||||
	conf, err := config.LoadConfig([]byte(configBytes))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("config loading error:", err)
 | 
			
		||||
	}
 | 
			
		||||
	if !conf.Valid() {
 | 
			
		||||
		t.Fatal("config is not valid")
 | 
			
		||||
	}
 | 
			
		||||
	return conf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newRemoteSigner(t *testing.T, policy *config.Signing) *Signer {
 | 
			
		||||
	s, err := NewSigner(policy)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("fail to init remote signer:", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newTestSignHandler(t *testing.T) (h http.Handler) {
 | 
			
		||||
	h, err := newHandler(t, testCaFile, testCaKeyFile, "sign")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newTestInfoHandler(t *testing.T) (h http.Handler) {
 | 
			
		||||
	h, err := newHandler(t, testCaFile, testCaKeyFile, "info")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newTestSignServer(t *testing.T) *httptest.Server {
 | 
			
		||||
	mux := http.NewServeMux()
 | 
			
		||||
	mux.Handle("/api/v1/cfssl/sign", newTestSignHandler(t))
 | 
			
		||||
	ts := httptest.NewUnstartedServer(mux)
 | 
			
		||||
	ts.Start()
 | 
			
		||||
	t.Log(ts.URL)
 | 
			
		||||
	return ts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newTestInfoServer(t *testing.T) *httptest.Server {
 | 
			
		||||
	mux := http.NewServeMux()
 | 
			
		||||
	mux.Handle("/api/v1/cfssl/info", newTestInfoHandler(t))
 | 
			
		||||
	ts := httptest.NewUnstartedServer(mux)
 | 
			
		||||
	ts.Start()
 | 
			
		||||
	t.Log(ts.URL)
 | 
			
		||||
	return ts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func closeTestServer(t *testing.T, ts *httptest.Server) {
 | 
			
		||||
	t.Log("Finalizing test server.")
 | 
			
		||||
	ts.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHandler generates a new sign handler (or info handler) using the certificate
 | 
			
		||||
// authority private key and certficate to sign certificates.
 | 
			
		||||
func newHandler(t *testing.T, caFile, caKeyFile, op string) (http.Handler, error) {
 | 
			
		||||
	var expiry = 1 * time.Minute
 | 
			
		||||
	var CAConfig = &config.Config{
 | 
			
		||||
		Signing: &config.Signing{
 | 
			
		||||
			Profiles: map[string]*config.SigningProfile{
 | 
			
		||||
				"signature": &config.SigningProfile{
 | 
			
		||||
					Usage:  []string{"digital signature"},
 | 
			
		||||
					Expiry: expiry,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			Default: &config.SigningProfile{
 | 
			
		||||
				Usage:        []string{"cert sign", "crl sign"},
 | 
			
		||||
				ExpiryString: "43800h",
 | 
			
		||||
				Expiry:       expiry,
 | 
			
		||||
				CA:           true,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	s, err := local.NewSignerFromFile(testCaFile, testCaKeyFile, CAConfig.Signing)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if op == "sign" {
 | 
			
		||||
		return NewSignHandlerFromSigner(s)
 | 
			
		||||
	} else if op == "info" {
 | 
			
		||||
		return info.NewHandler(s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.Fatal("Bad op code")
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSignHandlerFromSigner generates a new SignHandler directly from
 | 
			
		||||
// an existing signer.
 | 
			
		||||
func NewSignHandlerFromSigner(s signer.Signer) (h http.Handler, err error) {
 | 
			
		||||
	policy := s.Policy()
 | 
			
		||||
	if policy == nil {
 | 
			
		||||
		err = errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Sign will only respond for profiles that have no auth provider.
 | 
			
		||||
	// So if all of the profiles require authentication, we return an error.
 | 
			
		||||
	haveUnauth := (policy.Default.Provider == nil)
 | 
			
		||||
	for _, profile := range policy.Profiles {
 | 
			
		||||
		if !haveUnauth {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		haveUnauth = (profile.Provider == nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !haveUnauth {
 | 
			
		||||
		err = errors.New(errors.PolicyError, errors.InvalidPolicy)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &api.HTTPHandler{
 | 
			
		||||
		Handler: &SignHandler{
 | 
			
		||||
			signer: s,
 | 
			
		||||
		},
 | 
			
		||||
		Method: "POST",
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A SignHandler accepts requests with a hostname and certficate
 | 
			
		||||
// parameter (which should be PEM-encoded) and returns a new signed
 | 
			
		||||
// certificate. It includes upstream servers indexed by their
 | 
			
		||||
// profile name.
 | 
			
		||||
type SignHandler struct {
 | 
			
		||||
	signer signer.Signer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handle responds to requests for the CA to sign the certificate request
 | 
			
		||||
// present in the "certificate_request" parameter for the host named
 | 
			
		||||
// in the "hostname" parameter. The certificate should be PEM-encoded. If
 | 
			
		||||
// provided, subject information from the "subject" parameter will be used
 | 
			
		||||
// in place of the subject information from the CSR.
 | 
			
		||||
func (h *SignHandler) Handle(w http.ResponseWriter, r *http.Request) error {
 | 
			
		||||
	log.Info("signature request received")
 | 
			
		||||
 | 
			
		||||
	body, err := ioutil.ReadAll(r.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	r.Body.Close()
 | 
			
		||||
 | 
			
		||||
	var req signer.SignRequest
 | 
			
		||||
	err = json.Unmarshal(body, &req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(req.Hosts) == 0 {
 | 
			
		||||
		return errors.NewBadRequestString("missing paratmeter 'hosts'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if req.Request == "" {
 | 
			
		||||
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var cert []byte
 | 
			
		||||
	var profile *config.SigningProfile
 | 
			
		||||
 | 
			
		||||
	policy := h.signer.Policy()
 | 
			
		||||
	if policy != nil && policy.Profiles != nil && req.Profile != "" {
 | 
			
		||||
		profile = policy.Profiles[req.Profile]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if profile == nil && policy != nil {
 | 
			
		||||
		profile = policy.Default
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if profile.Provider != nil {
 | 
			
		||||
		log.Error("profile requires authentication")
 | 
			
		||||
		return errors.NewBadRequestString("authentication required")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cert, err = h.signer.Sign(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warningf("failed to sign request: %v", err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := map[string]string{"certificate": string(cert)}
 | 
			
		||||
	log.Info("wrote response")
 | 
			
		||||
	return api.SendResponse(w, result)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/testdata/ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/testdata/ca.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEmzCCA4OgAwIBAgIMAMSvNBgypwaaSQ5iMA0GCSqGSIb3DQEBBQUAMIGMMQsw
 | 
			
		||||
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
 | 
			
		||||
YW5jaXNjbzETMBEGA1UEChMKQ0ZTU0wgVEVTVDEbMBkGA1UEAxMSQ0ZTU0wgVEVT
 | 
			
		||||
VCBSb290IENBMR4wHAYJKoZIhvcNAQkBFg90ZXN0QHRlc3QubG9jYWwwHhcNMTIx
 | 
			
		||||
MjEyMDIxMDMxWhcNMjIxMDIxMDIxMDMxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNV
 | 
			
		||||
BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoT
 | 
			
		||||
CkNGU1NMIFRFU1QxGzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqG
 | 
			
		||||
SIb3DQEJARYPdGVzdEB0ZXN0LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
 | 
			
		||||
MIIBCgKCAQEAsRp1xSfIDoD/40Bo4Hls3sFn4dav5NgxbZGpVyGF7dJI9u0eEnL4
 | 
			
		||||
BUGssPaUFLWC83CZxujUEiEfE0oKX+uOhhGv3+j5xSTNM764m2eSiN53cdZtK05d
 | 
			
		||||
hwq9uS8LtjKOQeN1mQ5qmiqxBMdjkKgMsVw5lMCgoYKo57kaKFyXzdpNVDzqw+pt
 | 
			
		||||
HWmuNtDQjK3qT5Ma06mYPmIGYhIZYLY7oJGg9ZEaNR0GIw4zIT5JRsNiaSb5wTLw
 | 
			
		||||
aa0n/4vLJyVjLJcYmJBvZWj8g+taK+C4INu/jGux+bmsC9hq14tbOaTNAn/NE0qN
 | 
			
		||||
8oHwcRBEqfOdEYdZkxI5NWPiKNW/Q+AeXQIDAQABo4H6MIH3MB0GA1UdDgQWBBS3
 | 
			
		||||
0veEuqg51fusEM4p/YuWpBPsvTCBxAYDVR0jBIG8MIG5gBS30veEuqg51fusEM4p
 | 
			
		||||
/YuWpBPsvaGBkqSBjzCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju
 | 
			
		||||
aWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEzARBgNVBAoTCkNGU1NMIFRFU1Qx
 | 
			
		||||
GzAZBgNVBAMTEkNGU1NMIFRFU1QgUm9vdCBDQTEeMBwGCSqGSIb3DQEJARYPdGVz
 | 
			
		||||
dEB0ZXN0LmxvY2FsggwAxK80GDKnBppJDmIwDwYDVR0TBAgwBgEB/wIBADANBgkq
 | 
			
		||||
hkiG9w0BAQUFAAOCAQEAJ7r1EZYDwed6rS0+YKHdkRGRQ5Rz6A9DIVBPXrSMAGj3
 | 
			
		||||
F5EF2m/GJbhpVbnNJTVlgP9DDyabOZNxzdrCr4cHMkYYnocDdgAodnkw6GZ/GJTc
 | 
			
		||||
depbVTR4TpihFNzeDEGJePrEwM1DouGswpu97jyuCYZ3z1a60+a+3C1GwWaJ7Aet
 | 
			
		||||
Uqm+yLTUrMISsfnDPqJdM1NeqW3jiZ4IgcqJkieCCSpag9Xuzrp9q6rjmePvlQkv
 | 
			
		||||
qz020JGg6VijJ+c6Tf5y0XqbAhkBTqYtVamu9gEth9utn12EhdNjTZMPKMjjgFUd
 | 
			
		||||
H0N6yOEuQMl4ky7RxZBM0iPyeob6i4z2LEQilgv9MQ==
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/testdata/ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										28
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote/testdata/ca_key.pem
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
-----BEGIN PRIVATE KEY-----
 | 
			
		||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxGnXFJ8gOgP/j
 | 
			
		||||
QGjgeWzewWfh1q/k2DFtkalXIYXt0kj27R4ScvgFQayw9pQUtYLzcJnG6NQSIR8T
 | 
			
		||||
Sgpf646GEa/f6PnFJM0zvribZ5KI3ndx1m0rTl2HCr25Lwu2Mo5B43WZDmqaKrEE
 | 
			
		||||
x2OQqAyxXDmUwKChgqjnuRooXJfN2k1UPOrD6m0daa420NCMrepPkxrTqZg+YgZi
 | 
			
		||||
EhlgtjugkaD1kRo1HQYjDjMhPklGw2JpJvnBMvBprSf/i8snJWMslxiYkG9laPyD
 | 
			
		||||
61or4Lgg27+Ma7H5uawL2GrXi1s5pM0Cf80TSo3ygfBxEESp850Rh1mTEjk1Y+Io
 | 
			
		||||
1b9D4B5dAgMBAAECggEAKHhjcSomDSptTwDo9mLI/h40HudwSlsc8GzYxZBjinUD
 | 
			
		||||
N2n39T9QbeMUE1xFenX/9qFEgq+xxnLLJx1EQacSapCgIAqdCO/f9HMgvGJumdg8
 | 
			
		||||
c0cMq1i9Bp7tu+OESZ5D48qWlOM2eQRIb08g8W11eRIaFmPuUPoKnuktkQuXpPJc
 | 
			
		||||
YbS/+JuA8SDwe6sV0cMCQuS+iHFfeGwWCKrDUkhLwcL3waW3od2XFyOeFFWFhl0h
 | 
			
		||||
HmM/mWKRuRdqR7hrmArTwFZVkB+o/1ywVYXIv+JQm0eNZ5PKLNJGL2f5oxbMR/JI
 | 
			
		||||
AoK0bAlJmYaFp96h1KpbPwLEL/0hHSWA7sAyJIgQAQKBgQDaEAZor/w4ZUTekT1+
 | 
			
		||||
cbId0yA+ikDXQOfXaNCSh9Pex+Psjd5zVVOqyVFJ29daRju3d7rmpN4Cm5V4h0l1
 | 
			
		||||
/2ad207rjCAnpCHtaddJWNyJzF2IL2IaoCZQRp0k7zOjBGQpoWDTwBaEin5CCv3P
 | 
			
		||||
kkdQkKz6FDP1xskHSLZr21/QCQKBgQDP6jXutEgGjf3yKpMFk/69EamJdon8clbt
 | 
			
		||||
hl7cOyWtobnZhdOWVZPe00Oo3Jag2aWgFFsm3EtwnUCnR4d4+fXRKS2LkhfIUZcz
 | 
			
		||||
cKy17Ileggdd8UGhL4RDrF/En9tJL86WcVkcoOrqLcGB2FLWrVhVpHFK74eLMCH/
 | 
			
		||||
uc/+ioPItQKBgHYoDsD08s7AGMQcoNx90MyWVLduhFnegoFW+wUa8jOZzieka6/E
 | 
			
		||||
wVQeR5yksZjpy3vLNYu6M83n7eLkM2rrm/fXGHlLcTTpm7SgEBZfPwivotKjEh5p
 | 
			
		||||
PrlqucWEk082lutz1RqHz+u7e1Rfzk2F7nx6GDBdeBYpw03eGXJx6QW5AoGBAIJq
 | 
			
		||||
4puyAEAET1fZNtHX7IGCk7sDXTi6LCbgE57HhzHr8V0t4fQ6CABMuvMwM1gATjEk
 | 
			
		||||
s6yjoLqqGUUUzDipanViBAy5fiuManC868lN7zkWDTLzQ3ytBqVAee4na/DziP27
 | 
			
		||||
ae9YTSLJwskE/alloLRP6zTbHUXE0n7LelmrX1DFAoGBAMFLl+Lu+WFgCHxBjn43
 | 
			
		||||
rHpJbQZQmsFhAMhkN4hsj6dJfAGn2gRLRiVRAika+8QF65xMZiVQWUVSUZADWERi
 | 
			
		||||
0SXGjzN1wYxO3Qzy3LYwws6fxFAq5lo79eb38yFT2lHdqK3x/QgiDSRVl+R6cExV
 | 
			
		||||
xQB518/lp2eIeMpglWByDwJX
 | 
			
		||||
-----END PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										320
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/signer.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							
							
						
						
									
										320
									
								
								Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/signer.go
								
								
									generated
								
								
									vendored
								
								
									Normal file
								
							| 
						 | 
				
			
			@ -0,0 +1,320 @@
 | 
			
		|||
// Package signer implements certificate signature functionality for CF-SSL.
 | 
			
		||||
package signer
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto"
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/rsa"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"crypto/x509"
 | 
			
		||||
	"crypto/x509/pkix"
 | 
			
		||||
	"encoding/asn1"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"math"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
 | 
			
		||||
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/csr"
 | 
			
		||||
	cferr "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MaxPathLen is the default path length for a new CA certificate.
 | 
			
		||||
var MaxPathLen = 2
 | 
			
		||||
 | 
			
		||||
// Subject contains the information that should be used to override the
 | 
			
		||||
// subject information when signing a certificate.
 | 
			
		||||
type Subject struct {
 | 
			
		||||
	CN    string
 | 
			
		||||
	Names []csr.Name `json:"names"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SignRequest stores a signature request, which contains the hostname,
 | 
			
		||||
// the CSR, optional subject information, and the signature profile.
 | 
			
		||||
type SignRequest struct {
 | 
			
		||||
	Hosts   []string `json:"hosts"`
 | 
			
		||||
	Request string   `json:"certificate_request"`
 | 
			
		||||
	Subject *Subject `json:"subject,omitempty"`
 | 
			
		||||
	Profile string   `json:"profile"`
 | 
			
		||||
	Label   string   `json:"label"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// appendIf appends to a if s is not an empty string.
 | 
			
		||||
func appendIf(s string, a *[]string) {
 | 
			
		||||
	if s != "" {
 | 
			
		||||
		*a = append(*a, s)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Name returns the PKIX name for the subject.
 | 
			
		||||
func (s *Subject) Name() pkix.Name {
 | 
			
		||||
	var name pkix.Name
 | 
			
		||||
	name.CommonName = s.CN
 | 
			
		||||
 | 
			
		||||
	for _, n := range s.Names {
 | 
			
		||||
		appendIf(n.C, &name.Country)
 | 
			
		||||
		appendIf(n.ST, &name.Province)
 | 
			
		||||
		appendIf(n.L, &name.Locality)
 | 
			
		||||
		appendIf(n.O, &name.Organization)
 | 
			
		||||
		appendIf(n.OU, &name.OrganizationalUnit)
 | 
			
		||||
	}
 | 
			
		||||
	return name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SplitHosts takes a comma-spearated list of hosts and returns a slice
 | 
			
		||||
// with the hosts split
 | 
			
		||||
func SplitHosts(hostList string) []string {
 | 
			
		||||
	return strings.Split(hostList, ",")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Signer contains a CA's certificate and private key for signing
 | 
			
		||||
// certificates, a Signing policy to refer to and a SignatureAlgorithm.
 | 
			
		||||
type Signer interface {
 | 
			
		||||
	Certificate(label, profile string) (*x509.Certificate, error)
 | 
			
		||||
	Policy() *config.Signing
 | 
			
		||||
	SetPolicy(*config.Signing)
 | 
			
		||||
	SigAlgo() x509.SignatureAlgorithm
 | 
			
		||||
	Sign(req SignRequest) (cert []byte, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DefaultSigAlgo returns an appropriate X.509 signature algorithm given
 | 
			
		||||
// the CA's private key.
 | 
			
		||||
func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
 | 
			
		||||
	pub := priv.Public()
 | 
			
		||||
	switch pub := pub.(type) {
 | 
			
		||||
	case *rsa.PublicKey:
 | 
			
		||||
		keySize := pub.N.BitLen()
 | 
			
		||||
		switch {
 | 
			
		||||
		case keySize >= 4096:
 | 
			
		||||
			return x509.SHA512WithRSA
 | 
			
		||||
		case keySize >= 3072:
 | 
			
		||||
			return x509.SHA384WithRSA
 | 
			
		||||
		case keySize >= 2048:
 | 
			
		||||
			return x509.SHA256WithRSA
 | 
			
		||||
		default:
 | 
			
		||||
			return x509.SHA1WithRSA
 | 
			
		||||
		}
 | 
			
		||||
	case *ecdsa.PublicKey:
 | 
			
		||||
		switch pub.Curve {
 | 
			
		||||
		case elliptic.P256():
 | 
			
		||||
			return x509.ECDSAWithSHA256
 | 
			
		||||
		case elliptic.P384():
 | 
			
		||||
			return x509.ECDSAWithSHA384
 | 
			
		||||
		case elliptic.P521():
 | 
			
		||||
			return x509.ECDSAWithSHA512
 | 
			
		||||
		default:
 | 
			
		||||
			return x509.ECDSAWithSHA1
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return x509.UnknownSignatureAlgorithm
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCertificateRequest takes an incoming certificate request and
 | 
			
		||||
// builds a certificate template from it. If not nil, the subject
 | 
			
		||||
// information from subject will be used in place of the information in
 | 
			
		||||
// the CSR. The same is true for the list of hosts.
 | 
			
		||||
func ParseCertificateRequest(s Signer, csrBytes []byte, sub *Subject, hosts []string) (template *x509.Certificate, err error) {
 | 
			
		||||
	csr, err := x509.ParseCertificateRequest(csrBytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = cferr.Wrap(cferr.CertificateError, cferr.KeyMismatch, err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template = &x509.Certificate{
 | 
			
		||||
		Subject:            csr.Subject,
 | 
			
		||||
		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
 | 
			
		||||
		PublicKey:          csr.PublicKey,
 | 
			
		||||
		SignatureAlgorithm: s.SigAlgo(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sub != nil {
 | 
			
		||||
		template.Subject = sub.Name()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range hosts {
 | 
			
		||||
		if ip := net.ParseIP(hosts[i]); ip != nil {
 | 
			
		||||
			template.IPAddresses = append(template.IPAddresses, ip)
 | 
			
		||||
		} else {
 | 
			
		||||
			template.DNSNames = append(template.DNSNames, hosts[i])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckSignature verifies a signature made by the key on a CSR, such
 | 
			
		||||
// as on the CSR itself.
 | 
			
		||||
func CheckSignature(csr *x509.CertificateRequest, algo x509.SignatureAlgorithm, signed, signature []byte) error {
 | 
			
		||||
	var hashType crypto.Hash
 | 
			
		||||
 | 
			
		||||
	switch algo {
 | 
			
		||||
	case x509.SHA1WithRSA, x509.ECDSAWithSHA1:
 | 
			
		||||
		hashType = crypto.SHA1
 | 
			
		||||
	case x509.SHA256WithRSA, x509.ECDSAWithSHA256:
 | 
			
		||||
		hashType = crypto.SHA256
 | 
			
		||||
	case x509.SHA384WithRSA, x509.ECDSAWithSHA384:
 | 
			
		||||
		hashType = crypto.SHA384
 | 
			
		||||
	case x509.SHA512WithRSA, x509.ECDSAWithSHA512:
 | 
			
		||||
		hashType = crypto.SHA512
 | 
			
		||||
	default:
 | 
			
		||||
		return x509.ErrUnsupportedAlgorithm
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !hashType.Available() {
 | 
			
		||||
		return x509.ErrUnsupportedAlgorithm
 | 
			
		||||
	}
 | 
			
		||||
	h := hashType.New()
 | 
			
		||||
 | 
			
		||||
	h.Write(signed)
 | 
			
		||||
	digest := h.Sum(nil)
 | 
			
		||||
 | 
			
		||||
	switch pub := csr.PublicKey.(type) {
 | 
			
		||||
	case *rsa.PublicKey:
 | 
			
		||||
		return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
 | 
			
		||||
	case *ecdsa.PublicKey:
 | 
			
		||||
		ecdsaSig := new(struct{ R, S *big.Int })
 | 
			
		||||
		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
 | 
			
		||||
			return errors.New("x509: ECDSA signature contained zero or negative values")
 | 
			
		||||
		}
 | 
			
		||||
		if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) {
 | 
			
		||||
			return errors.New("x509: ECDSA verification failure")
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return x509.ErrUnsupportedAlgorithm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type subjectPublicKeyInfo struct {
 | 
			
		||||
	Algorithm        pkix.AlgorithmIdentifier
 | 
			
		||||
	SubjectPublicKey asn1.BitString
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ComputeSKI derives an SKI from the certificate's public key in a
 | 
			
		||||
// standard manner. This is done by computing the SHA-1 digest of the
 | 
			
		||||
// SubjectPublicKeyInfo component of the certificate.
 | 
			
		||||
func ComputeSKI(template *x509.Certificate) ([]byte, error) {
 | 
			
		||||
	pub := template.PublicKey
 | 
			
		||||
	encodedPub, err := x509.MarshalPKIXPublicKey(pub)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var subPKI subjectPublicKeyInfo
 | 
			
		||||
	_, err = asn1.Unmarshal(encodedPub, &subPKI)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pubHash := sha1.Sum(subPKI.SubjectPublicKey.Bytes)
 | 
			
		||||
	return pubHash[:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FillTemplate is a utility function that tries to load as much of
 | 
			
		||||
// the certificate template as possible from the profiles and current
 | 
			
		||||
// template. It fills in the key uses, expiration, revocation URLs,
 | 
			
		||||
// serial number, and SKI.
 | 
			
		||||
func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile) error {
 | 
			
		||||
	ski, err := ComputeSKI(template)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		eku             []x509.ExtKeyUsage
 | 
			
		||||
		ku              x509.KeyUsage
 | 
			
		||||
		backdate        time.Duration
 | 
			
		||||
		expiry          time.Duration
 | 
			
		||||
		notBefore       time.Time
 | 
			
		||||
		notAfter        time.Time
 | 
			
		||||
		crlURL, ocspURL string
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// The third value returned from Usages is a list of unknown key usages.
 | 
			
		||||
	// This should be used when validating the profile at load, and isn't used
 | 
			
		||||
	// here.
 | 
			
		||||
	ku, eku, _ = profile.Usages()
 | 
			
		||||
	if profile.IssuerURL == nil {
 | 
			
		||||
		profile.IssuerURL = defaultProfile.IssuerURL
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ku == 0 && len(eku) == 0 {
 | 
			
		||||
		return cferr.New(cferr.PolicyError, cferr.NoKeyUsages)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if expiry = profile.Expiry; expiry == 0 {
 | 
			
		||||
		expiry = defaultProfile.Expiry
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if crlURL = profile.CRL; crlURL == "" {
 | 
			
		||||
		crlURL = defaultProfile.CRL
 | 
			
		||||
	}
 | 
			
		||||
	if ocspURL = profile.OCSP; ocspURL == "" {
 | 
			
		||||
		ocspURL = defaultProfile.OCSP
 | 
			
		||||
	}
 | 
			
		||||
	if backdate = profile.Backdate; backdate == 0 {
 | 
			
		||||
		backdate = -5 * time.Minute
 | 
			
		||||
	} else {
 | 
			
		||||
		backdate = -1 * profile.Backdate
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !profile.NotBefore.IsZero() {
 | 
			
		||||
		notBefore = profile.NotBefore.UTC()
 | 
			
		||||
	} else {
 | 
			
		||||
		notBefore = time.Now().Round(time.Minute).Add(backdate).UTC()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !profile.NotAfter.IsZero() {
 | 
			
		||||
		notAfter = profile.NotAfter.UTC()
 | 
			
		||||
	} else {
 | 
			
		||||
		notAfter = notBefore.Add(expiry).UTC()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template.SerialNumber = serialNumber
 | 
			
		||||
	template.NotBefore = notBefore
 | 
			
		||||
	template.NotAfter = notAfter
 | 
			
		||||
	template.KeyUsage = ku
 | 
			
		||||
	template.ExtKeyUsage = eku
 | 
			
		||||
	template.BasicConstraintsValid = true
 | 
			
		||||
	template.IsCA = profile.CA
 | 
			
		||||
	template.SubjectKeyId = ski
 | 
			
		||||
 | 
			
		||||
	if ocspURL != "" {
 | 
			
		||||
		template.OCSPServer = []string{ocspURL}
 | 
			
		||||
	}
 | 
			
		||||
	if crlURL != "" {
 | 
			
		||||
		template.CRLDistributionPoints = []string{crlURL}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(profile.IssuerURL) != 0 {
 | 
			
		||||
		template.IssuingCertificateURL = profile.IssuerURL
 | 
			
		||||
	}
 | 
			
		||||
	if len(profile.Policies) != 0 {
 | 
			
		||||
		template.PolicyIdentifiers = profile.Policies
 | 
			
		||||
	}
 | 
			
		||||
	if profile.OCSPNoCheck {
 | 
			
		||||
		ocspNoCheckExtension := pkix.Extension{
 | 
			
		||||
			Id:       asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5},
 | 
			
		||||
			Critical: false,
 | 
			
		||||
			Value:    []byte{0x05, 0x00},
 | 
			
		||||
		}
 | 
			
		||||
		template.ExtraExtensions = append(template.ExtraExtensions, ocspNoCheckExtension)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue