vendor
This commit is contained in:
parent
f92c531f5d
commit
4d889632f6
8
go.mod
Normal file
8
go.mod
Normal file
@ -0,0 +1,8 @@
|
||||
module novit.nc/direktil/local-server
|
||||
|
||||
require (
|
||||
github.com/cavaliercoder/go-cpio v0.0.0-20180222193108-9caab6ff29df
|
||||
github.com/cloudflare/cfssl v0.0.0-20180530085446-275fb308ac70
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
|
||||
novit.nc/direktil/pkg v0.0.0-20180617064658-ec3736cedc38
|
||||
)
|
3
vendor/github.com/cavaliercoder/go-cpio/.gitignore
generated
vendored
Normal file
3
vendor/github.com/cavaliercoder/go-cpio/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.fuzz/
|
||||
*.zip
|
||||
|
10
vendor/github.com/cavaliercoder/go-cpio/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/cavaliercoder/go-cpio/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.4
|
||||
- 1.6.4
|
||||
- 1.7.6
|
||||
- 1.8.3
|
||||
|
||||
script: make check
|
26
vendor/github.com/cavaliercoder/go-cpio/LICENSE
generated
vendored
Normal file
26
vendor/github.com/cavaliercoder/go-cpio/LICENSE
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2017 Ryan Armstrong. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
18
vendor/github.com/cavaliercoder/go-cpio/Makefile
generated
vendored
Normal file
18
vendor/github.com/cavaliercoder/go-cpio/Makefile
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
PACKAGE = github.com/cavaliercoder/go-cpio
|
||||
|
||||
all: check
|
||||
|
||||
check:
|
||||
go test -v
|
||||
|
||||
cpio-fuzz.zip: *.go
|
||||
go-fuzz-build $(PACKAGE)
|
||||
|
||||
fuzz: cpio-fuzz.zip
|
||||
go-fuzz -bin=./cpio-fuzz.zip -workdir=.fuzz/
|
||||
|
||||
clean-fuzz:
|
||||
rm -rf cpio-fuzz.zip .fuzz/crashers/* .fuzz/suppressions/*
|
||||
|
||||
|
||||
.PHONY: all check
|
62
vendor/github.com/cavaliercoder/go-cpio/README.md
generated
vendored
Normal file
62
vendor/github.com/cavaliercoder/go-cpio/README.md
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
# go-cpio [![GoDoc](https://godoc.org/github.com/cavaliercoder/go-cpio?status.svg)](https://godoc.org/github.com/cavaliercoder/go-cpio) [![Build Status](https://travis-ci.org/cavaliercoder/go-cpio.svg?branch=master)](https://travis-ci.org/cavaliercoder/go-cpio) [![Go Report Card](https://goreportcard.com/badge/github.com/cavaliercoder/go-cpio)](https://goreportcard.com/report/github.com/cavaliercoder/go-cpio)
|
||||
|
||||
This package provides a Go native implementation of the CPIO archive file
|
||||
format.
|
||||
|
||||
Currently, only the SVR4 (New ASCII) format is supported, both with and without
|
||||
checksums.
|
||||
|
||||
```go
|
||||
// Create a buffer to write our archive to.
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Create a new cpio archive.
|
||||
w := cpio.NewWriter(buf)
|
||||
|
||||
// Add some files to the archive.
|
||||
var files = []struct {
|
||||
Name, Body string
|
||||
}{
|
||||
{"readme.txt", "This archive contains some text files."},
|
||||
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
||||
{"todo.txt", "Get animal handling license."},
|
||||
}
|
||||
for _, file := range files {
|
||||
hdr := &cpio.Header{
|
||||
Name: file.Name,
|
||||
Mode: 0600,
|
||||
Size: int64(len(file.Body)),
|
||||
}
|
||||
if err := w.WriteHeader(hdr); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if _, err := w.Write([]byte(file.Body)); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
// Make sure to check the error on Close.
|
||||
if err := w.Close(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Open the cpio archive for reading.
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
r := cpio.NewReader(b)
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err == io.EOF {
|
||||
// end of cpio archive
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Printf("Contents of %s:\n", hdr.Name)
|
||||
if _, err := io.Copy(os.Stdout, r); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
```
|
8
vendor/github.com/cavaliercoder/go-cpio/cpio.go
generated
vendored
Normal file
8
vendor/github.com/cavaliercoder/go-cpio/cpio.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
Package cpio implements access to CPIO archives. Currently, only the SVR4 (New
|
||||
ASCII) format is supported, both with and without checksums.
|
||||
|
||||
References:
|
||||
https://www.freebsd.org/cgi/man.cgi?query=cpio&sektion=5
|
||||
*/
|
||||
package cpio
|
77
vendor/github.com/cavaliercoder/go-cpio/example_test.go
generated
vendored
Normal file
77
vendor/github.com/cavaliercoder/go-cpio/example_test.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
package cpio_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/cavaliercoder/go-cpio"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
// Create a buffer to write our archive to.
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
// Create a new cpio archive.
|
||||
w := cpio.NewWriter(buf)
|
||||
|
||||
// Add some files to the archive.
|
||||
var files = []struct {
|
||||
Name, Body string
|
||||
}{
|
||||
{"readme.txt", "This archive contains some text files."},
|
||||
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
||||
{"todo.txt", "Get animal handling license."},
|
||||
}
|
||||
for _, file := range files {
|
||||
hdr := &cpio.Header{
|
||||
Name: file.Name,
|
||||
Mode: 0600,
|
||||
Size: int64(len(file.Body)),
|
||||
}
|
||||
if err := w.WriteHeader(hdr); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if _, err := w.Write([]byte(file.Body)); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
// Make sure to check the error on Close.
|
||||
if err := w.Close(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Open the cpio archive for reading.
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
r := cpio.NewReader(b)
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err == io.EOF {
|
||||
// end of cpio archive
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Printf("Contents of %s:\n", hdr.Name)
|
||||
if _, err := io.Copy(os.Stdout, r); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Contents of readme.txt:
|
||||
// This archive contains some text files.
|
||||
// Contents of gopher.txt:
|
||||
// Gopher names:
|
||||
// George
|
||||
// Geoffrey
|
||||
// Gonzo
|
||||
// Contents of todo.txt:
|
||||
// Get animal handling license.
|
||||
}
|
75
vendor/github.com/cavaliercoder/go-cpio/fileinfo.go
generated
vendored
Normal file
75
vendor/github.com/cavaliercoder/go-cpio/fileinfo.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
|
||||
// headerFileInfo implements os.FileInfo.
|
||||
type headerFileInfo struct {
|
||||
h *Header
|
||||
}
|
||||
|
||||
// Name returns the base name of the file.
|
||||
func (fi headerFileInfo) Name() string {
|
||||
if fi.IsDir() {
|
||||
return path.Base(path.Clean(fi.h.Name))
|
||||
}
|
||||
return path.Base(fi.h.Name)
|
||||
}
|
||||
|
||||
func (fi headerFileInfo) Size() int64 { return fi.h.Size }
|
||||
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
|
||||
func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
|
||||
func (fi headerFileInfo) Sys() interface{} { return fi.h }
|
||||
|
||||
func (fi headerFileInfo) Mode() (mode os.FileMode) {
|
||||
// Set file permission bits.
|
||||
mode = os.FileMode(fi.h.Mode).Perm()
|
||||
|
||||
// Set setuid, setgid and sticky bits.
|
||||
if fi.h.Mode&ModeSetuid != 0 {
|
||||
// setuid
|
||||
mode |= os.ModeSetuid
|
||||
}
|
||||
if fi.h.Mode&ModeSetgid != 0 {
|
||||
// setgid
|
||||
mode |= os.ModeSetgid
|
||||
}
|
||||
if fi.h.Mode&ModeSticky != 0 {
|
||||
// sticky
|
||||
mode |= os.ModeSticky
|
||||
}
|
||||
|
||||
// Set file mode bits.
|
||||
// clear perm, setuid, setgid and sticky bits.
|
||||
m := os.FileMode(fi.h.Mode) & 0170000
|
||||
if m == ModeDir {
|
||||
// directory
|
||||
mode |= os.ModeDir
|
||||
}
|
||||
if m == ModeNamedPipe {
|
||||
// named pipe (FIFO)
|
||||
mode |= os.ModeNamedPipe
|
||||
}
|
||||
if m == ModeSymlink {
|
||||
// symbolic link
|
||||
mode |= os.ModeSymlink
|
||||
}
|
||||
if m == ModeDevice {
|
||||
// device file
|
||||
mode |= os.ModeDevice
|
||||
}
|
||||
if m == ModeCharDevice {
|
||||
// Unix character device
|
||||
mode |= os.ModeDevice
|
||||
mode |= os.ModeCharDevice
|
||||
}
|
||||
if m == ModeSocket {
|
||||
// Unix domain socket
|
||||
mode |= os.ModeSocket
|
||||
}
|
||||
|
||||
return mode
|
||||
}
|
35
vendor/github.com/cavaliercoder/go-cpio/fuzz.go
generated
vendored
Normal file
35
vendor/github.com/cavaliercoder/go-cpio/fuzz.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// +build gofuzz
|
||||
|
||||
package cpio
|
||||
|
||||
import "bytes"
|
||||
import "io"
|
||||
|
||||
// Fuzz tests the parsing and error handling of random byte arrays using
|
||||
// https://github.com/dvyukov/go-fuzz.
|
||||
func Fuzz(data []byte) int {
|
||||
r := NewReader(bytes.NewReader(data))
|
||||
h := NewHash()
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err != nil {
|
||||
if hdr != nil {
|
||||
panic("hdr != nil on error")
|
||||
}
|
||||
if err == io.EOF {
|
||||
// everything worked with random input... interesting
|
||||
return 1
|
||||
}
|
||||
// error returned for random input. Good!
|
||||
return -1
|
||||
}
|
||||
|
||||
// hash file
|
||||
h.Reset()
|
||||
io.CopyN(h, r, hdr.Size)
|
||||
h.Sum32()
|
||||
|
||||
// convert file header
|
||||
FileInfoHeader(hdr.FileInfo())
|
||||
}
|
||||
}
|
45
vendor/github.com/cavaliercoder/go-cpio/hash.go
generated
vendored
Normal file
45
vendor/github.com/cavaliercoder/go-cpio/hash.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
)
|
||||
|
||||
type digest struct {
|
||||
sum uint32
|
||||
}
|
||||
|
||||
// NewHash returns a new hash.Hash32 computing the SVR4 checksum.
|
||||
func NewHash() hash.Hash32 {
|
||||
return &digest{}
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
for _, b := range p {
|
||||
d.sum += uint32(b & 0xFF)
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum(b []byte) []byte {
|
||||
out := [4]byte{}
|
||||
binary.LittleEndian.PutUint32(out[:], d.sum)
|
||||
return append(b, out[:]...)
|
||||
}
|
||||
|
||||
func (d *digest) Sum32() uint32 {
|
||||
return d.sum
|
||||
}
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.sum = 0
|
||||
}
|
||||
|
||||
func (d *digest) Size() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int {
|
||||
return 1
|
||||
}
|
152
vendor/github.com/cavaliercoder/go-cpio/header.go
generated
vendored
Normal file
152
vendor/github.com/cavaliercoder/go-cpio/header.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Mode constants from the cpio spec.
|
||||
const (
|
||||
ModeSetuid = 04000 // Set uid
|
||||
ModeSetgid = 02000 // Set gid
|
||||
ModeSticky = 01000 // Save text (sticky bit)
|
||||
ModeDir = 040000 // Directory
|
||||
ModeNamedPipe = 010000 // FIFO
|
||||
ModeRegular = 0100000 // Regular file
|
||||
ModeSymlink = 0120000 // Symbolic link
|
||||
ModeDevice = 060000 // Block special file
|
||||
ModeCharDevice = 020000 // Character special file
|
||||
ModeSocket = 0140000 // Socket
|
||||
|
||||
ModeType = 0170000 // Mask for the type bits
|
||||
ModePerm = 0777 // Unix permission bits
|
||||
)
|
||||
|
||||
const (
|
||||
// headerEOF is the value of the filename of the last header in a CPIO archive.
|
||||
headerEOF = "TRAILER!!!"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrHeader = errors.New("cpio: invalid cpio header")
|
||||
)
|
||||
|
||||
// A FileMode represents a file's mode and permission bits.
|
||||
type FileMode int64
|
||||
|
||||
func (m FileMode) String() string {
|
||||
return fmt.Sprintf("%#o", m)
|
||||
}
|
||||
|
||||
// IsDir reports whether m describes a directory. That is, it tests for the
|
||||
// ModeDir bit being set in m.
|
||||
func (m FileMode) IsDir() bool {
|
||||
return m&ModeDir != 0
|
||||
}
|
||||
|
||||
// IsRegular reports whether m describes a regular file. That is, it tests for
|
||||
// the ModeRegular bit being set in m.
|
||||
func (m FileMode) IsRegular() bool {
|
||||
return m&^ModePerm == ModeRegular
|
||||
}
|
||||
|
||||
// Perm returns the Unix permission bits in m.
|
||||
func (m FileMode) Perm() FileMode {
|
||||
return m & ModePerm
|
||||
}
|
||||
|
||||
// Checksum is the sum of all bytes in the file data. This sum is computed
|
||||
// treating all bytes as unsigned values and using unsigned arithmetic. Only
|
||||
// the least-significant 32 bits of the sum are stored. Use NewHash to compute
|
||||
// the actual checksum of an archived file.
|
||||
type Checksum uint32
|
||||
|
||||
func (c Checksum) String() string {
|
||||
return fmt.Sprintf("%08X", uint32(c))
|
||||
}
|
||||
|
||||
// A Header represents a single header in a CPIO archive.
|
||||
type Header struct {
|
||||
DeviceID int
|
||||
Inode int64 // inode number
|
||||
Mode FileMode // permission and mode bits
|
||||
UID int // user id of the owner
|
||||
GID int // group id of the owner
|
||||
Links int // number of inbound links
|
||||
ModTime time.Time // modified time
|
||||
Size int64 // size in bytes
|
||||
Name string // filename
|
||||
Linkname string // target name of link
|
||||
Checksum Checksum // computed checksum
|
||||
|
||||
pad int64 // bytes to pad before next header
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo for the Header.
|
||||
func (h *Header) FileInfo() os.FileInfo {
|
||||
return headerFileInfo{h}
|
||||
}
|
||||
|
||||
// FileInfoHeader creates a partially-populated Header from fi.
|
||||
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
||||
// If fi describes a directory, a slash is appended to the name.
|
||||
// Because os.FileInfo's Name method returns only the base name of
|
||||
// the file it describes, it may be necessary to modify the Name field
|
||||
// of the returned header to provide the full path name of the file.
|
||||
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
||||
if fi == nil {
|
||||
return nil, errors.New("cpio: FileInfo is nil")
|
||||
}
|
||||
|
||||
if sys, ok := fi.Sys().(*Header); ok {
|
||||
// This FileInfo came from a Header (not the OS). Return a copy of the
|
||||
// original Header.
|
||||
h := &Header{}
|
||||
*h = *sys
|
||||
return h, nil
|
||||
}
|
||||
|
||||
fm := fi.Mode()
|
||||
h := &Header{
|
||||
Name: fi.Name(),
|
||||
Mode: FileMode(fi.Mode().Perm()), // or'd with Mode* constants later
|
||||
ModTime: fi.ModTime(),
|
||||
Size: fi.Size(),
|
||||
}
|
||||
|
||||
switch {
|
||||
case fm.IsRegular():
|
||||
h.Mode |= ModeRegular
|
||||
case fi.IsDir():
|
||||
h.Mode |= ModeDir
|
||||
h.Name += "/"
|
||||
case fm&os.ModeSymlink != 0:
|
||||
h.Mode |= ModeSymlink
|
||||
h.Linkname = link
|
||||
case fm&os.ModeDevice != 0:
|
||||
if fm&os.ModeCharDevice != 0 {
|
||||
h.Mode |= ModeCharDevice
|
||||
} else {
|
||||
h.Mode |= ModeDevice
|
||||
}
|
||||
case fm&os.ModeNamedPipe != 0:
|
||||
h.Mode |= ModeNamedPipe
|
||||
case fm&os.ModeSocket != 0:
|
||||
h.Mode |= ModeSocket
|
||||
default:
|
||||
return nil, fmt.Errorf("cpio: unknown file mode %v", fm)
|
||||
}
|
||||
if fm&os.ModeSetuid != 0 {
|
||||
h.Mode |= ModeSetuid
|
||||
}
|
||||
if fm&os.ModeSetgid != 0 {
|
||||
h.Mode |= ModeSetgid
|
||||
}
|
||||
if fm&os.ModeSticky != 0 {
|
||||
h.Mode |= ModeSticky
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
72
vendor/github.com/cavaliercoder/go-cpio/reader.go
generated
vendored
Normal file
72
vendor/github.com/cavaliercoder/go-cpio/reader.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// A Reader provides sequential access to the contents of a CPIO archive. A CPIO
|
||||
// archive consists of a sequence of files. The Next method advances to the next
|
||||
// file in the archive (including the first), and then it can be treated as an
|
||||
// io.Reader to access the file's data.
|
||||
type Reader struct {
|
||||
r io.Reader // underlying file reader
|
||||
hdr *Header // current Header
|
||||
eof int64 // bytes until the end of the current file
|
||||
}
|
||||
|
||||
// NewReader creates a new Reader reading from r.
|
||||
func NewReader(r io.Reader) *Reader {
|
||||
return &Reader{
|
||||
r: r,
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads from the current entry in the CPIO archive. It returns 0, io.EOF
|
||||
// when it reaches the end of that entry, until Next is called to advance to the
|
||||
// next entry.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
if r.hdr == nil || r.eof == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
rn := len(p)
|
||||
if r.eof < int64(rn) {
|
||||
rn = int(r.eof)
|
||||
}
|
||||
n, err = r.r.Read(p[0:rn])
|
||||
r.eof -= int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
// Next advances to the next entry in the CPIO archive.
|
||||
// io.EOF is returned at the end of the input.
|
||||
func (r *Reader) Next() (*Header, error) {
|
||||
if r.hdr == nil {
|
||||
return r.next()
|
||||
}
|
||||
skp := r.eof + r.hdr.pad
|
||||
if skp > 0 {
|
||||
_, err := io.CopyN(ioutil.Discard, r.r, skp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return r.next()
|
||||
}
|
||||
|
||||
func (r *Reader) next() (*Header, error) {
|
||||
r.eof = 0
|
||||
hdr, err := readHeader(r.r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.hdr = hdr
|
||||
r.eof = hdr.Size
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
// ReadHeader creates a new Header, reading from r.
|
||||
func readHeader(r io.Reader) (*Header, error) {
|
||||
// currently only SVR4 format is supported
|
||||
return readSVR4Header(r)
|
||||
}
|
145
vendor/github.com/cavaliercoder/go-cpio/svr4.go
generated
vendored
Normal file
145
vendor/github.com/cavaliercoder/go-cpio/svr4.go
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
svr4MaxNameSize = 4096 // MAX_PATH
|
||||
svr4MaxFileSize = 4294967295
|
||||
)
|
||||
|
||||
var svr4Magic = []byte{0x30, 0x37, 0x30, 0x37, 0x30, 0x31} // 07070
|
||||
|
||||
func readHex(s string) int64 {
|
||||
// errors are ignored and 0 returned
|
||||
i, _ := strconv.ParseInt(s, 16, 64)
|
||||
return i
|
||||
}
|
||||
|
||||
func writeHex(b []byte, i int64) {
|
||||
// i needs to be in range of uint32
|
||||
copy(b, fmt.Sprintf("%08X", i))
|
||||
}
|
||||
|
||||
func readSVR4Header(r io.Reader) (*Header, error) {
|
||||
var buf [110]byte
|
||||
if _, err := io.ReadFull(r, buf[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: check endianness
|
||||
|
||||
// check magic
|
||||
hasCRC := false
|
||||
if !bytes.HasPrefix(buf[:], svr4Magic[:5]) {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
if buf[5] == 0x32 { // '2'
|
||||
hasCRC = true
|
||||
} else if buf[5] != 0x31 { // '1'
|
||||
return nil, ErrHeader
|
||||
}
|
||||
|
||||
asc := string(buf[:])
|
||||
hdr := &Header{}
|
||||
|
||||
hdr.Inode = readHex(asc[6:14])
|
||||
hdr.Mode = FileMode(readHex(asc[14:22]))
|
||||
hdr.UID = int(readHex(asc[22:30]))
|
||||
hdr.GID = int(readHex(asc[30:38]))
|
||||
hdr.Links = int(readHex(asc[38:46]))
|
||||
hdr.ModTime = time.Unix(readHex(asc[46:54]), 0)
|
||||
hdr.Size = readHex(asc[54:62])
|
||||
if hdr.Size > svr4MaxFileSize {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
nameSize := readHex(asc[94:102])
|
||||
if nameSize < 1 || nameSize > svr4MaxNameSize {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
hdr.Checksum = Checksum(readHex(asc[102:110]))
|
||||
if !hasCRC && hdr.Checksum != 0 {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
|
||||
name := make([]byte, nameSize)
|
||||
if _, err := io.ReadFull(r, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Name = string(name[:nameSize-1])
|
||||
if hdr.Name == headerEOF {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
// store padding between end of file and next header
|
||||
hdr.pad = (4 - (hdr.Size % 4)) % 4
|
||||
|
||||
// skip to end of header/start of file
|
||||
pad := (4 - (len(buf)+len(name))%4) % 4
|
||||
if pad > 0 {
|
||||
if _, err := io.ReadFull(r, buf[:pad]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// read link name
|
||||
if hdr.Mode&^ModePerm == ModeSymlink {
|
||||
if hdr.Size < 1 || hdr.Size > svr4MaxNameSize {
|
||||
return nil, ErrHeader
|
||||
}
|
||||
b := make([]byte, hdr.Size)
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Linkname = string(b)
|
||||
hdr.Size = 0
|
||||
}
|
||||
|
||||
return hdr, nil
|
||||
}
|
||||
|
||||
func writeSVR4Header(w io.Writer, hdr *Header) (pad int64, err error) {
|
||||
var hdrBuf [110]byte
|
||||
for i := 0; i < len(hdrBuf); i++ {
|
||||
hdrBuf[i] = '0'
|
||||
}
|
||||
copy(hdrBuf[:], svr4Magic)
|
||||
writeHex(hdrBuf[6:14], hdr.Inode)
|
||||
writeHex(hdrBuf[14:22], int64(hdr.Mode))
|
||||
writeHex(hdrBuf[22:30], int64(hdr.UID))
|
||||
writeHex(hdrBuf[30:38], int64(hdr.GID))
|
||||
writeHex(hdrBuf[38:46], int64(hdr.Links))
|
||||
if !hdr.ModTime.IsZero() {
|
||||
writeHex(hdrBuf[46:54], hdr.ModTime.Unix())
|
||||
}
|
||||
writeHex(hdrBuf[54:62], hdr.Size)
|
||||
writeHex(hdrBuf[94:102], int64(len(hdr.Name)+1))
|
||||
|
||||
// write header
|
||||
_, err = w.Write(hdrBuf[:])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// write filename
|
||||
_, err = io.WriteString(w, hdr.Name+"\x00")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// pad to end of filename
|
||||
npad := (4 - ((len(hdrBuf) + len(hdr.Name) + 1) % 4)) % 4
|
||||
_, err = w.Write(zeroBlock[:npad])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// compute padding to end of file
|
||||
pad = (4 - (hdr.Size % 4)) % 4
|
||||
return
|
||||
}
|
121
vendor/github.com/cavaliercoder/go-cpio/svr4_test.go
generated
vendored
Normal file
121
vendor/github.com/cavaliercoder/go-cpio/svr4_test.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var files = []struct {
|
||||
Name, Body string
|
||||
}{
|
||||
{"./gophers.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
|
||||
{"./readme.txt", "This archive contains some text files."},
|
||||
{"./todo.txt", "Get animal handling license."},
|
||||
}
|
||||
|
||||
func TestRead(t *testing.T) {
|
||||
f, err := os.Open("testdata/test_svr4_crc.cpio")
|
||||
if err != nil {
|
||||
t.Fatalf("error opening test file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := NewReader(f)
|
||||
for {
|
||||
_, err := r.Next()
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("error moving to next header: %v", err)
|
||||
return
|
||||
}
|
||||
// TODO: validate header fields
|
||||
}
|
||||
}
|
||||
|
||||
func TestSVR4CRC(t *testing.T) {
|
||||
f, err := os.Open("testdata/test_svr4_crc.cpio")
|
||||
if err != nil {
|
||||
t.Fatalf("error opening test file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
w := NewHash()
|
||||
r := NewReader(f)
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
t.Errorf("error moving to next header: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if hdr.Mode.IsRegular() {
|
||||
w.Reset()
|
||||
_, err = io.CopyN(w, r, hdr.Size)
|
||||
if err != nil {
|
||||
t.Fatalf("error writing to checksum hash: %v", err)
|
||||
}
|
||||
|
||||
sum := Checksum(w.Sum32())
|
||||
if sum != hdr.Checksum {
|
||||
t.Errorf("expected checksum %v, got %v for %v", hdr.Checksum, sum, hdr.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleNewHash() {
|
||||
// Open the cpio archive for reading.
|
||||
f, err := os.Open("testdata/test_svr4_crc.cpio")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
r := NewReader(f)
|
||||
|
||||
// create a Hash
|
||||
h := NewHash()
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
for {
|
||||
hdr, err := r.Next()
|
||||
if err == io.EOF {
|
||||
// end of cpio archive
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// skip symlinks, directories, etc.
|
||||
if !hdr.Mode.IsRegular() {
|
||||
continue
|
||||
}
|
||||
|
||||
// read file into hash
|
||||
h.Reset()
|
||||
_, err = io.CopyN(h, r, hdr.Size)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// check hash matches header checksum
|
||||
sum := Checksum(h.Sum32())
|
||||
if sum == hdr.Checksum {
|
||||
fmt.Printf("Checksum OK: %v (%v)\n", hdr.Name, hdr.Checksum)
|
||||
} else {
|
||||
fmt.Printf("Checksum FAIL: %v - expected %v, got %v\n", hdr.Name, hdr.Checksum, sum)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Checksum OK: gophers.txt (00000C98)
|
||||
// Checksum OK: readme.txt (00000E3D)
|
||||
// Checksum OK: todo.txt (00000A52)
|
||||
}
|
26
vendor/github.com/cavaliercoder/go-cpio/testdata/Makefile
generated
vendored
Normal file
26
vendor/github.com/cavaliercoder/go-cpio/testdata/Makefile
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
SOURCES = \
|
||||
gophers.txt \
|
||||
readme.txt \
|
||||
todo.txt \
|
||||
checklist.txt
|
||||
|
||||
ARCHIVES = \
|
||||
test_odc.cpio \
|
||||
test_svr4.cpio \
|
||||
test_svr4_crc.cpio
|
||||
|
||||
all: $(ARCHIVES)
|
||||
|
||||
test_odc.cpio: $(SOURCES)
|
||||
echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=odc > $@
|
||||
|
||||
test_svr4.cpio: $(SOURCES)
|
||||
echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=newc > $@
|
||||
|
||||
test_svr4_crc.cpio: $(SOURCES)
|
||||
echo $(SOURCES) | tr " " "\n" | cpio -o --owner=0:0 --format=crc > $@
|
||||
|
||||
clean:
|
||||
rm -f $(ARCHIVES) version.txt
|
||||
|
||||
.PHONY: all clean
|
1
vendor/github.com/cavaliercoder/go-cpio/testdata/checklist.txt
generated
vendored
Normal file
1
vendor/github.com/cavaliercoder/go-cpio/testdata/checklist.txt
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
todo.txt
|
4
vendor/github.com/cavaliercoder/go-cpio/testdata/gophers.txt
generated
vendored
Normal file
4
vendor/github.com/cavaliercoder/go-cpio/testdata/gophers.txt
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
Gopher names:
|
||||
George
|
||||
Geoffrey
|
||||
Gonzo
|
1
vendor/github.com/cavaliercoder/go-cpio/testdata/readme.txt
generated
vendored
Normal file
1
vendor/github.com/cavaliercoder/go-cpio/testdata/readme.txt
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
This archive contains some text files.
|
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_odc.cpio
generated
vendored
Normal file
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_odc.cpio
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4.cpio
generated
vendored
Normal file
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4.cpio
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4_crc.cpio
generated
vendored
Normal file
BIN
vendor/github.com/cavaliercoder/go-cpio/testdata/test_svr4_crc.cpio
generated
vendored
Normal file
Binary file not shown.
1
vendor/github.com/cavaliercoder/go-cpio/testdata/todo.txt
generated
vendored
Normal file
1
vendor/github.com/cavaliercoder/go-cpio/testdata/todo.txt
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
Get animal handling license.
|
128
vendor/github.com/cavaliercoder/go-cpio/writer.go
generated
vendored
Normal file
128
vendor/github.com/cavaliercoder/go-cpio/writer.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
package cpio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrWriteTooLong = errors.New("cpio: write too long")
|
||||
ErrWriteAfterClose = errors.New("cpio: write after close")
|
||||
)
|
||||
|
||||
var trailer = &Header{
|
||||
Name: string(headerEOF),
|
||||
Links: 1,
|
||||
}
|
||||
|
||||
var zeroBlock [4]byte
|
||||
|
||||
// A Writer provides sequential writing of a CPIO archive. A CPIO archive
|
||||
// consists of a sequence of files. Call WriteHeader to begin a new file, and
|
||||
// then call Write to supply that file's data, writing at most hdr.Size bytes in
|
||||
// total.
|
||||
type Writer struct {
|
||||
w io.Writer
|
||||
nb int64 // number of unwritten bytes for current file entry
|
||||
pad int64 // amount of padding to write after current file entry
|
||||
inode int64
|
||||
err error
|
||||
closed bool
|
||||
}
|
||||
|
||||
// NewWriter creates a new Writer writing to w.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
return &Writer{w: w}
|
||||
}
|
||||
|
||||
// Flush finishes writing the current file (optional).
|
||||
func (w *Writer) Flush() error {
|
||||
if w.nb > 0 {
|
||||
w.err = fmt.Errorf("cpio: missed writing %d bytes", w.nb)
|
||||
return w.err
|
||||
}
|
||||
_, w.err = w.w.Write(zeroBlock[:w.pad])
|
||||
if w.err != nil {
|
||||
return w.err
|
||||
}
|
||||
w.nb = 0
|
||||
w.pad = 0
|
||||
return w.err
|
||||
}
|
||||
|
||||
// WriteHeader writes hdr and prepares to accept the file's contents.
|
||||
// WriteHeader calls Flush if it is not the first header. Calling after a Close
|
||||
// will return ErrWriteAfterClose.
|
||||
func (w *Writer) WriteHeader(hdr *Header) (err error) {
|
||||
if w.closed {
|
||||
return ErrWriteAfterClose
|
||||
}
|
||||
if w.err == nil {
|
||||
w.Flush()
|
||||
}
|
||||
if w.err != nil {
|
||||
return w.err
|
||||
}
|
||||
|
||||
if hdr.Name != headerEOF {
|
||||
// TODO: should we be mutating hdr here?
|
||||
// ensure all inodes are unique
|
||||
w.inode++
|
||||
if hdr.Inode == 0 {
|
||||
hdr.Inode = w.inode
|
||||
}
|
||||
|
||||
// ensure file type is set
|
||||
if hdr.Mode&^ModePerm == 0 {
|
||||
hdr.Mode |= ModeRegular
|
||||
}
|
||||
|
||||
// ensure regular files have at least 1 inbound link
|
||||
if hdr.Links < 1 && hdr.Mode.IsRegular() {
|
||||
hdr.Links = 1
|
||||
}
|
||||
}
|
||||
|
||||
w.nb = hdr.Size
|
||||
w.pad, w.err = writeSVR4Header(w.w, hdr)
|
||||
return
|
||||
}
|
||||
|
||||
// Write writes to the current entry in the CPIO archive. Write returns the
|
||||
// error ErrWriteTooLong if more than hdr.Size bytes are written after
|
||||
// WriteHeader.
|
||||
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||
if w.closed {
|
||||
err = ErrWriteAfterClose
|
||||
return
|
||||
}
|
||||
overwrite := false
|
||||
if int64(len(p)) > w.nb {
|
||||
p = p[0:w.nb]
|
||||
overwrite = true
|
||||
}
|
||||
n, err = w.w.Write(p)
|
||||
w.nb -= int64(n)
|
||||
if err == nil && overwrite {
|
||||
err = ErrWriteTooLong
|
||||
return
|
||||
}
|
||||
w.err = err
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the CPIO archive, flushing any unwritten data to the underlying
|
||||
// writer.
|
||||
func (w *Writer) Close() error {
|
||||
if w.err != nil || w.closed {
|
||||
return w.err
|
||||
}
|
||||
w.err = w.WriteHeader(trailer)
|
||||
if w.err != nil {
|
||||
return w.err
|
||||
}
|
||||
w.Flush()
|
||||
w.closed = true
|
||||
return w.err
|
||||
}
|
94
vendor/github.com/cloudflare/cfssl/auth/auth.go
generated
vendored
Normal file
94
vendor/github.com/cloudflare/cfssl/auth/auth.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
if splitKey := strings.SplitN(key, ":", 2); len(splitKey) == 2 {
|
||||
switch splitKey[0] {
|
||||
case "env":
|
||||
key = os.Getenv(splitKey[1])
|
||||
case "file":
|
||||
data, err := ioutil.ReadFile(splitKey[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key = string(data)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown key prefix: %s", splitKey[0])
|
||||
}
|
||||
}
|
||||
|
||||
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
vendor/github.com/cloudflare/cfssl/auth/auth_test.go
generated
vendored
Normal file
159
vendor/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
vendor/github.com/cloudflare/cfssl/auth/testdata/authrequest.json
generated
vendored
Normal file
1
vendor/github.com/cloudflare/cfssl/auth/testdata/authrequest.json
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"token": "tSU1WTE/322iXrOBfJSQ9/u1dleqpwUmCj1LXYHw07Y=", "request": "ewoJImhvc3RuYW1lIjogImt5bGVpc29tLm5ldCIsCgkicmVxdWVzdCI6ICItLS0tLUJFR0lOIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQoJICAgIE1JSUQwVENDQWpzQ0FRQXdZREVMTUFrR0ExVUVCaE1DVlZNeEVqQVFCZ05WQkFvVENXUnliM0J6YjI1a1pURVEKCSAgICBNQTRHQTFVRUN4TUhRMFl0UTJoaGRERVdNQlFHQTFVRUJ4TU5VMkZ1SUVaeVlXNWphWE5qYnpFVE1CRUdBMVVFCgkgICAgQ0JNS1EyRnNhV1p2Y201cFlUQ0NBYUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0dQQURDQ0FZb0NnZ0dCQU1jQwoJICAgIEdCbDVMVHJla0dGV2hvdGtkYlorUjFNbG9hcld4UXY5alA0QWVrdDhVT2ljeXBIdkZPNnhPdFN3SG8rcjMyaUUKCSAgICBxblM1eXYvMDFQMk1KdXlxbmRuY1RTTXNPbFQvN242N1RNMDB1MDFLLzljL3NvZ0tFS2pseXBsVFA3eUZkRy9jCgkgICAgT3UvOXFLYi9KYWxkMndFTEZZRTZ4cTJSREZ5eHlpWk9CM2c3WjdGeGE1ZDZhZGZHUndaek50VUw0LzhzK0x5aQoJICAgIHFkdzlJMWZrUWQ2MDRwb1pGTjB3clFzNGxmaFdUVWZnMHJIdWg1d2dHS1AzVnpacGJ0OEZiMXZOamZiSHRvaHgKCSAgICBHMlBDVTZKeStEYzFiU2ZVeldjUW5lbnA4NThXNEY4ejdwRjV5YmRuRlIzMTNIam9zcVhuRzI4eklUck9hZE1UCgkgICAgSGFKNnpPaGdFYWZVT1dYT3pqTm9mRkJGYTJJdUNBVCtJVFJZMXRDL2dxcHhHd0gveXVWTjE5Qkc4VXBuMCtIQQoJICAgIGllMm1LQ0hmU0JBS1QvWGU0dW1QZWF4U2JJcVdzVzhjaytkM2I0b3I5Ulp2NWNaUmNUM29pa0p0K1NRRzY5cFcKCSAgICA0T0FiYitBQnNzL05JdXJpNnowZTdERWVJTDV6bXlTSnFkdFlIZE5ZTjcrK3Y5eEJOc0w0SXNVNklFeTMrUUlECgkgICAgQVFBQm9DNHdMQVlKS29aSWh2Y05BUWtPTVI4d0hUQWJCZ05WSFJFRUZEQVNnaEJqWmk1a2NtOXdjMjl1WkdVdQoJICAgIGJtVjBNQXNHQ1NxR1NJYjNEUUVCREFPQ0FZRUFoTUFxQmlySStrMWFVM2xmQUdRaVNtOHl0T3paaWozODloSXIKCSAgICBuVXA4K1duVHVWVGI4WFozL1YrTDlFblRJbUY2dTF3ZWFqWGQzU3VlNDk1NzBMYlltSXV4QmtHcDUwL0JkVUR6CgkgICAgdUI2eHNoaEpXczEySnhVYjkxSW1tMGJUUncyek1xZXdnYTZmdHpaL0FLNG1zeFFBMlVJYmNXWmRzS2J1TTdzbwoJICAgIEpUZlZXOWlPd3FIdC82NFpqNHRCWmY5THpPRHI3a051S0tMbndqaXpIMTg3eGZJSWhkcmpGOFdTN0g5QVBCMU8KCSAgICBTdUVVRGZxaDBTV1IzbHRXdUF1VVdlbzZTS2NIVnVzeS9HNFlFK1BCeXcxZVY3RzRTYmVHNVowbytHT1VVSy9GCgkgICAgYjU1R21XMXhhNExBcnMxQSt6ZUZidkovQkFwc2JVMmI2V1ZtTmE3V3BIejdXWElGT0p1WUpnRWtWS1BKbkt1cwoJICAgIHFxczNGZ1VxejBadjdUSzhtTWlFVEpvWFpzNnpDdk15c1FldTNKL29qZ3RBanZNaHpRYzZQUy9udk90SmRJZysKCSAgICBIMHFYNDlmaHAxQnJZeXNsYWx6UUlGMCtIMHFTVWV5b1V5VjJ3YkxCQUxhcHhNZnZUVmxoTnduYWN0Y0tReHE0CgkgICAgK3dUKzJQVEowYk0vNUFWMFRPMVNQVDBBVmlKaAoJICAgIC0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLSIsCgkicHJvZmlsZSI6ICIiLAoJInJlbW90ZSI6ICIiLAoJImxhYmVsIjogInByaW1hcnkiCn0KCg=="}
|
30
vendor/github.com/cloudflare/cfssl/auth/testdata/request.json
generated
vendored
Normal file
30
vendor/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"
|
||||
}
|
||||
|
75
vendor/github.com/cloudflare/cfssl/certdb/README.md
generated
vendored
Normal file
75
vendor/github.com/cloudflare/cfssl/certdb/README.md
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
# certdb usage
|
||||
|
||||
Using a database enables additional functionality for existing commands when a
|
||||
db config is provided:
|
||||
|
||||
- `sign` and `gencert` add a certificate to the certdb after signing it
|
||||
- `serve` enables database functionality for the sign and revoke endpoints
|
||||
|
||||
A database is required for the following:
|
||||
|
||||
- `revoke` marks certificates revoked in the database with an optional reason
|
||||
- `ocsprefresh` refreshes the table of cached OCSP responses
|
||||
- `ocspdump` outputs cached OCSP responses in a concatenated base64-encoded format
|
||||
|
||||
## Setup/Migration
|
||||
|
||||
This directory stores [goose](https://bitbucket.org/liamstask/goose/) db migration scripts for various DB backends.
|
||||
Currently supported:
|
||||
- MySQL in mysql
|
||||
- PostgreSQL in pg
|
||||
- SQLite in sqlite
|
||||
|
||||
### Get goose
|
||||
|
||||
go get bitbucket.org/liamstask/goose/cmd/goose
|
||||
|
||||
### Use goose to start and terminate a MySQL DB
|
||||
To start a MySQL using goose:
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql up
|
||||
|
||||
To tear down a MySQL DB using goose
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql down
|
||||
|
||||
Note: the administration of MySQL DB is not included. We assume
|
||||
the databases being connected to are already created and access control
|
||||
is properly handled.
|
||||
|
||||
### Use goose to start and terminate a PostgreSQL DB
|
||||
To start a PostgreSQL using goose:
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/pg up
|
||||
|
||||
To tear down a PostgreSQL DB using goose
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/pg down
|
||||
|
||||
Note: the administration of PostgreSQL DB is not included. We assume
|
||||
the databases being connected to are already created and access control
|
||||
is properly handled.
|
||||
|
||||
### Use goose to start and terminate a SQLite DB
|
||||
To start a SQLite DB using goose:
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up
|
||||
|
||||
To tear down a SQLite DB using goose
|
||||
|
||||
goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
|
||||
|
||||
## CFSSL Configuration
|
||||
|
||||
Several cfssl commands take a -db-config flag. Create a file with a
|
||||
JSON dictionary:
|
||||
|
||||
{"driver":"sqlite3","data_source":"certs.db"}
|
||||
|
||||
or
|
||||
|
||||
{"driver":"postgres","data_source":"postgres://user:password@host/db"}
|
||||
|
||||
or
|
||||
|
||||
{"driver":"mysql","data_source":"user:password@tcp(hostname:3306)/db?parseTime=true"}
|
42
vendor/github.com/cloudflare/cfssl/certdb/certdb.go
generated
vendored
Normal file
42
vendor/github.com/cloudflare/cfssl/certdb/certdb.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package certdb
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CertificateRecord encodes a certificate and its metadata
|
||||
// that will be recorded in a database.
|
||||
type CertificateRecord struct {
|
||||
Serial string `db:"serial_number"`
|
||||
AKI string `db:"authority_key_identifier"`
|
||||
CALabel string `db:"ca_label"`
|
||||
Status string `db:"status"`
|
||||
Reason int `db:"reason"`
|
||||
Expiry time.Time `db:"expiry"`
|
||||
RevokedAt time.Time `db:"revoked_at"`
|
||||
PEM string `db:"pem"`
|
||||
}
|
||||
|
||||
// OCSPRecord encodes a OCSP response body and its metadata
|
||||
// that will be recorded in a database.
|
||||
type OCSPRecord struct {
|
||||
Serial string `db:"serial_number"`
|
||||
AKI string `db:"authority_key_identifier"`
|
||||
Body string `db:"body"`
|
||||
Expiry time.Time `db:"expiry"`
|
||||
}
|
||||
|
||||
// Accessor abstracts the CRUD of certdb objects from a DB.
|
||||
type Accessor interface {
|
||||
InsertCertificate(cr CertificateRecord) error
|
||||
GetCertificate(serial, aki string) ([]CertificateRecord, error)
|
||||
GetUnexpiredCertificates() ([]CertificateRecord, error)
|
||||
GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error)
|
||||
GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error)
|
||||
RevokeCertificate(serial, aki string, reasonCode int) error
|
||||
InsertOCSP(rr OCSPRecord) error
|
||||
GetOCSP(serial, aki string) ([]OCSPRecord, error)
|
||||
GetUnexpiredOCSPs() ([]OCSPRecord, error)
|
||||
UpdateOCSP(serial, aki, body string, expiry time.Time) error
|
||||
UpsertOCSP(serial, aki, body string, expiry time.Time) error
|
||||
}
|
659
vendor/github.com/cloudflare/cfssl/config/config.go
generated
vendored
Normal file
659
vendor/github.com/cloudflare/cfssl/config/config.go
generated
vendored
Normal file
@ -0,0 +1,659 @@
|
||||
// Package config contains the configuration logic for CFSSL.
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/auth"
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
ocspConfig "github.com/cloudflare/cfssl/ocsp/config"
|
||||
)
|
||||
|
||||
// A CSRWhitelist stores booleans for fields in the CSR. If a CSRWhitelist is
|
||||
// not present in a SigningProfile, all of these fields may be copied from the
|
||||
// CSR into the signed certificate. If a CSRWhitelist *is* present in a
|
||||
// SigningProfile, only those fields with a `true` value in the CSRWhitelist may
|
||||
// be copied from the CSR to the signed certificate. Note that some of these
|
||||
// fields, like Subject, can be provided or partially provided through the API.
|
||||
// Since API clients are expected to be trusted, but CSRs are not, fields
|
||||
// provided through the API are not subject to whitelisting through this
|
||||
// mechanism.
|
||||
type CSRWhitelist struct {
|
||||
Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool
|
||||
DNSNames, IPAddresses, EmailAddresses bool
|
||||
}
|
||||
|
||||
// OID is our own version of asn1's ObjectIdentifier, so we can define a custom
|
||||
// JSON marshal / unmarshal.
|
||||
type OID asn1.ObjectIdentifier
|
||||
|
||||
// CertificatePolicy represents the ASN.1 PolicyInformation structure from
|
||||
// https://tools.ietf.org/html/rfc3280.html#page-106.
|
||||
// Valid values of Type are "id-qt-unotice" and "id-qt-cps"
|
||||
type CertificatePolicy struct {
|
||||
ID OID
|
||||
Qualifiers []CertificatePolicyQualifier
|
||||
}
|
||||
|
||||
// CertificatePolicyQualifier represents a single qualifier from an ASN.1
|
||||
// PolicyInformation structure.
|
||||
type CertificatePolicyQualifier struct {
|
||||
Type string
|
||||
Value string
|
||||
}
|
||||
|
||||
// AuthRemote is an authenticated remote signer.
|
||||
type AuthRemote struct {
|
||||
RemoteName string `json:"remote"`
|
||||
AuthKeyName string `json:"auth_key"`
|
||||
}
|
||||
|
||||
// CAConstraint specifies various CA constraints on the signed certificate.
|
||||
// CAConstraint would verify against (and override) the CA
|
||||
// extensions in the given CSR.
|
||||
type CAConstraint struct {
|
||||
IsCA bool `json:"is_ca"`
|
||||
MaxPathLen int `json:"max_path_len"`
|
||||
MaxPathLenZero bool `json:"max_path_len_zero"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
CAConstraint CAConstraint `json:"ca_constraint"`
|
||||
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"`
|
||||
NameWhitelistString string `json:"name_whitelist"`
|
||||
AuthRemote AuthRemote `json:"auth_remote"`
|
||||
CTLogServers []string `json:"ct_log_servers"`
|
||||
AllowedExtensions []OID `json:"allowed_extensions"`
|
||||
CertStore string `json:"cert_store"`
|
||||
|
||||
Policies []CertificatePolicy
|
||||
Expiry time.Duration
|
||||
Backdate time.Duration
|
||||
Provider auth.Provider
|
||||
RemoteProvider auth.Provider
|
||||
RemoteServer string
|
||||
RemoteCAs *x509.CertPool
|
||||
ClientCert *tls.Certificate
|
||||
CSRWhitelist *CSRWhitelist
|
||||
NameWhitelist *regexp.Regexp
|
||||
ExtensionWhitelist map[string]bool
|
||||
ClientProvidesSerialNumbers bool
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON string into an OID.
|
||||
func (oid *OID) UnmarshalJSON(data []byte) (err error) {
|
||||
if data[0] != '"' || data[len(data)-1] != '"' {
|
||||
return errors.New("OID JSON string not wrapped in quotes." + string(data))
|
||||
}
|
||||
data = data[1 : len(data)-1]
|
||||
parsedOid, err := parseObjectIdentifier(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*oid = OID(parsedOid)
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalJSON marshals an oid into a JSON string.
|
||||
func (oid OID) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf(`"%v"`, asn1.ObjectIdentifier(oid))), nil
|
||||
}
|
||||
|
||||
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 == "" && p.AuthRemote.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.Policies) > 0 {
|
||||
for _, policy := range p.Policies {
|
||||
for _, qualifier := range policy.Qualifiers {
|
||||
if qualifier.Type != "" && qualifier.Type != "id-qt-unotice" && qualifier.Type != "id-qt-cps" {
|
||||
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
|
||||
errors.New("invalid policy qualifier type"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if p.RemoteName != "" {
|
||||
log.Debug("match remote in profile to remotes section")
|
||||
if p.AuthRemote.RemoteName != "" {
|
||||
log.Error("profile has both a remote and an auth remote specified")
|
||||
return cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
|
||||
}
|
||||
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"))
|
||||
}
|
||||
} else {
|
||||
log.Debug("match auth remote in profile to remotes section")
|
||||
if remote := cfg.Remotes[p.AuthRemote.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"))
|
||||
}
|
||||
}
|
||||
|
||||
if p.AuthRemote.AuthKeyName != "" {
|
||||
log.Debug("match auth remote key in profile to auth_keys section")
|
||||
if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
|
||||
if key.Type == "standard" {
|
||||
p.RemoteProvider, 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_remote's auth_key in auth_keys section"))
|
||||
}
|
||||
}
|
||||
|
||||
if p.NameWhitelistString != "" {
|
||||
log.Debug("compiling whitelist regular expression")
|
||||
rule, err := regexp.Compile(p.NameWhitelistString)
|
||||
if err != nil {
|
||||
return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
|
||||
errors.New("failed to compile name whitelist section"))
|
||||
}
|
||||
p.NameWhitelist = rule
|
||||
}
|
||||
|
||||
p.ExtensionWhitelist = map[string]bool{}
|
||||
for _, oid := range p.AllowedExtensions {
|
||||
p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// SetClientCertKeyPairFromFile updates the properties to set client certificates for mutual
|
||||
// authenticated TLS remote requests
|
||||
func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error {
|
||||
if certFile != "" && keyFile != "" {
|
||||
cert, err := helpers.LoadClientCertificate(certFile, keyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, profile := range p.Profiles {
|
||||
profile.ClientCert = cert
|
||||
}
|
||||
p.Default.ClientCert = cert
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRemoteCAsFromFile reads root CAs from file and updates the properties to set remote CAs for TLS
|
||||
// remote requests
|
||||
func (p *Signing) SetRemoteCAsFromFile(caFile string) error {
|
||||
if caFile != "" {
|
||||
remoteCAs, err := helpers.LoadPEMCertPool(caFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.SetRemoteCAs(remoteCAs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRemoteCAs updates the properties to set remote CAs for TLS
|
||||
// remote requests
|
||||
func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) {
|
||||
for _, profile := range p.Profiles {
|
||||
profile.RemoteCAs = remoteCAs
|
||||
}
|
||||
p.Default.RemoteCAs = remoteCAs
|
||||
}
|
||||
|
||||
// NeedsRemoteSigner returns true if one of the profiles has a remote set
|
||||
func (p *Signing) NeedsRemoteSigner() bool {
|
||||
for _, profile := range p.Profiles {
|
||||
if profile.RemoteServer != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if p.Default.RemoteServer != "" {
|
||||
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.RemoteServer == "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if p.Default.RemoteServer == "" {
|
||||
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.AuthRemote.RemoteName == "" && p.AuthRemote.AuthKeyName != "" {
|
||||
log.Debugf("invalid auth remote profile: no remote signer specified")
|
||||
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
|
||||
}
|
||||
|
||||
if p.AuthRemote.RemoteName != "" {
|
||||
log.Debugf("invalid remote profile: auth remote is also specified")
|
||||
return false
|
||||
}
|
||||
} else if p.AuthRemote.RemoteName != "" {
|
||||
log.Debugf("validate auth remote profile")
|
||||
if p.RemoteServer == "" {
|
||||
log.Debugf("invalid auth remote profile: no remote signer specified")
|
||||
return false
|
||||
}
|
||||
|
||||
if p.AuthRemote.AuthKeyName == "" || p.RemoteProvider == nil {
|
||||
log.Debugf("invalid auth remote profile: no auth key is defined")
|
||||
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
|
||||
}
|
||||
|
||||
// This checks if the SigningProfile object contains configurations that are only effective with a local signer
|
||||
// which has access to CA private key.
|
||||
func (p *SigningProfile) hasLocalConfig() bool {
|
||||
if p.Usage != nil ||
|
||||
p.IssuerURL != nil ||
|
||||
p.OCSP != "" ||
|
||||
p.ExpiryString != "" ||
|
||||
p.BackdateString != "" ||
|
||||
p.CAConstraint.IsCA != false ||
|
||||
!p.NotBefore.IsZero() ||
|
||||
!p.NotAfter.IsZero() ||
|
||||
p.NameWhitelistString != "" ||
|
||||
len(p.CTLogServers) != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// warnSkippedSettings prints a log warning message about skipped settings
|
||||
// in a SigningProfile, usually due to remote signer.
|
||||
func (p *Signing) warnSkippedSettings() {
|
||||
const warningMessage = `The configuration value by "usages", "issuer_urls", "ocsp_url", "crl_url", "ca_constraint", "expiry", "backdate", "not_before", "not_after", "cert_store" and "ct_log_servers" are skipped`
|
||||
if p == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if (p.Default.RemoteName != "" || p.Default.AuthRemote.RemoteName != "") && p.Default.hasLocalConfig() {
|
||||
log.Warning("default profile points to a remote signer: ", warningMessage)
|
||||
}
|
||||
|
||||
for name, profile := range p.Profiles {
|
||||
if (profile.RemoteName != "" || profile.AuthRemote.RemoteName != "") && profile.hasLocalConfig() {
|
||||
log.Warningf("Profiles[%s] points to a remote signer: %s", name, warningMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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"`
|
||||
OCSP *ocspConfig.Config `json:"ocsp"`
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
p.warnSkippedSettings()
|
||||
|
||||
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 commitment": x509.KeyUsageContentCommitment,
|
||||
"key encipherment": x509.KeyUsageKeyEncipherment,
|
||||
"key agreement": x509.KeyUsageKeyAgreement,
|
||||
"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: "+err.Error()))
|
||||
}
|
||||
|
||||
if cfg.Signing == nil {
|
||||
return nil, errors.New("No \"signing\" field present")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
537
vendor/github.com/cloudflare/cfssl/config/config_test.go
generated
vendored
Normal file
537
vendor/github.com/cloudflare/cfssl/config/config_test.go
generated
vendored
Normal file
@ -0,0 +1,537 @@
|
||||
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 validMinimalRemoteConfig2 = `
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"auth_remote":{
|
||||
"auth_key": "sample",
|
||||
"remote": "localhost"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_keys": {
|
||||
"sample": {
|
||||
"type":"standard",
|
||||
"key":"0123456789ABCDEF0123456789ABCDEF"
|
||||
}
|
||||
},
|
||||
"remotes": {
|
||||
"localhost": "127.0.0.1:8888"
|
||||
}
|
||||
}`
|
||||
|
||||
var invalidConflictRemoteConfig = `
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"auth_remote":{
|
||||
"auth_key": "sample",
|
||||
"remote": "localhost"
|
||||
},
|
||||
"remote": "localhost"
|
||||
}
|
||||
},
|
||||
"auth_keys": {
|
||||
"sample": {
|
||||
"type":"standard",
|
||||
"key":"0123456789ABCDEF0123456789ABCDEF"
|
||||
}
|
||||
},
|
||||
"remotes": {
|
||||
"localhost": "127.0.0.1:8888"
|
||||
}
|
||||
}`
|
||||
|
||||
var invalidRemoteConfig = `
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"auth_remotes_typos":{
|
||||
"auth_key": "sample",
|
||||
"remote": "localhost"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_keys": {
|
||||
"sample": {
|
||||
"type":"standard",
|
||||
"key":"0123456789ABCDEF0123456789ABCDEF"
|
||||
}
|
||||
},
|
||||
"remotes": {
|
||||
"localhost": "127.0.0.1:8888"
|
||||
}
|
||||
}`
|
||||
|
||||
var invalidAuthRemoteConfigMissingRemote = `
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"auth_remote":{
|
||||
"auth_key": "sample"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth_keys": {
|
||||
"sample": {
|
||||
"type":"standard",
|
||||
"key":"0123456789ABCDEF0123456789ABCDEF"
|
||||
}
|
||||
},
|
||||
"remotes": {
|
||||
"localhost": "127.0.0.1:8888"
|
||||
}
|
||||
}`
|
||||
|
||||
var invalidAuthRemoteConfigMissingKey = `
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"auth_remote":{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
var validLocalConfigsWithCAConstraint = []string{
|
||||
`{
|
||||
"signing": {
|
||||
"default": {
|
||||
"usages": ["digital signature", "email protection"],
|
||||
"ca_constraint": { "is_ca": true },
|
||||
"expiry": "8000h"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"signing": {
|
||||
"default": {
|
||||
"usages": ["digital signature", "email protection"],
|
||||
"ca_constraint": { "is_ca": true, "max_path_len": 1 },
|
||||
"expiry": "8000h"
|
||||
}
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"signing": {
|
||||
"default": {
|
||||
"usages": ["digital signature", "email protection"],
|
||||
"ca_constraint": { "is_ca": true, "max_path_len_zero": true },
|
||||
"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().")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAuthRemoteConfig(t *testing.T) {
|
||||
c, err := LoadConfig([]byte(validMinimalRemoteConfig2))
|
||||
if err != nil {
|
||||
t.Fatal("load valid config failed:", err)
|
||||
}
|
||||
|
||||
if c.Signing.Default.RemoteServer != "127.0.0.1:8888" {
|
||||
t.Fatal("load valid config failed: incorrect remote server")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDuplicateRemoteConfig(t *testing.T) {
|
||||
_, err := LoadConfig([]byte(invalidConflictRemoteConfig))
|
||||
if err == nil {
|
||||
t.Fatal("fail to reject invalid config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadAuthRemoteConfig(t *testing.T) {
|
||||
_, err := LoadConfig([]byte(invalidRemoteConfig))
|
||||
if err == nil {
|
||||
t.Fatal("load invalid config should failed")
|
||||
}
|
||||
|
||||
_, err = LoadConfig([]byte(invalidAuthRemoteConfigMissingRemote))
|
||||
if err == nil {
|
||||
t.Fatal("load invalid config should failed")
|
||||
}
|
||||
|
||||
_, err = LoadConfig([]byte(invalidAuthRemoteConfigMissingKey))
|
||||
if err == nil {
|
||||
t.Fatal("load invalid config should failed")
|
||||
}
|
||||
|
||||
var p *Signing
|
||||
if p.Valid() {
|
||||
t.Fatal("nil Signing config should be invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidCAConstraint(t *testing.T) {
|
||||
for _, config := range validLocalConfigsWithCAConstraint {
|
||||
_, err := LoadConfig([]byte(config))
|
||||
if err != nil {
|
||||
t.Fatal("can't parse valid ca constraint")
|
||||
}
|
||||
}
|
||||
}
|
27
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_auth.json
generated
vendored
Normal file
27
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_auth_bad_key.json
generated
vendored
Normal file
27
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_config.json
generated
vendored
Normal file
17
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_default.json
generated
vendored
Normal file
18
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_no_auth_keys.json
generated
vendored
Normal file
23
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_no_remotes.json
generated
vendored
Normal file
24
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_profile.json
generated
vendored
Normal file
18
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_remotes.json
generated
vendored
Normal file
27
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/invalid_usage.json
generated
vendored
Normal file
18
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/valid_config.json
generated
vendored
Normal file
24
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/valid_config_auth.json
generated
vendored
Normal file
29
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/valid_config_auth_no_default.json
generated
vendored
Normal file
19
vendor/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
vendor/github.com/cloudflare/cfssl/config/testdata/valid_config_no_default.json
generated
vendored
Normal file
14
vendor/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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
188
vendor/github.com/cloudflare/cfssl/crypto/pkcs7/pkcs7.go
generated
vendored
Normal file
188
vendor/github.com/cloudflare/cfssl/crypto/pkcs7/pkcs7.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
// Package pkcs7 implements the subset of the CMS PKCS #7 datatype that is typically
|
||||
// used to package certificates and CRLs. Using openssl, every certificate converted
|
||||
// to PKCS #7 format from another encoding such as PEM conforms to this implementation.
|
||||
// reference: https://www.openssl.org/docs/man1.1.0/apps/crl2pkcs7.html
|
||||
//
|
||||
// PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
|
||||
//
|
||||
// The full pkcs#7 cryptographic message syntax allows for cryptographic enhancements,
|
||||
// for example data can be encrypted and signed and then packaged through pkcs#7 to be
|
||||
// sent over a network and then verified and decrypted. It is asn1, and the type of
|
||||
// PKCS #7 ContentInfo, which comprises the PKCS #7 structure, is:
|
||||
//
|
||||
// ContentInfo ::= SEQUENCE {
|
||||
// contentType ContentType,
|
||||
// content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
|
||||
// }
|
||||
//
|
||||
// There are 6 possible ContentTypes, data, signedData, envelopedData,
|
||||
// signedAndEnvelopedData, digestedData, and encryptedData. Here signedData, Data, and encrypted
|
||||
// Data are implemented, as the degenerate case of signedData without a signature is the typical
|
||||
// format for transferring certificates and CRLS, and Data and encryptedData are used in PKCS #12
|
||||
// formats.
|
||||
// The ContentType signedData has the form:
|
||||
//
|
||||
//
|
||||
// signedData ::= SEQUENCE {
|
||||
// version Version,
|
||||
// digestAlgorithms DigestAlgorithmIdentifiers,
|
||||
// contentInfo ContentInfo,
|
||||
// certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL
|
||||
// crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
|
||||
// signerInfos SignerInfos
|
||||
// }
|
||||
//
|
||||
// As of yet signerInfos and digestAlgorithms are not parsed, as they are not relevant to
|
||||
// this system's use of PKCS #7 data. Version is an integer type, note that PKCS #7 is
|
||||
// recursive, this second layer of ContentInfo is similar ignored for our degenerate
|
||||
// usage. The ExtendedCertificatesAndCertificates type consists of a sequence of choices
|
||||
// between PKCS #6 extended certificates and x509 certificates. Any sequence consisting
|
||||
// of any number of extended certificates is not yet supported in this implementation.
|
||||
//
|
||||
// The ContentType Data is simply a raw octet string and is parsed directly into a Go []byte slice.
|
||||
//
|
||||
// The ContentType encryptedData is the most complicated and its form can be gathered by
|
||||
// the go type below. It essentially contains a raw octet string of encrypted data and an
|
||||
// algorithm identifier for use in decrypting this data.
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
)
|
||||
|
||||
// Types used for asn1 Unmarshaling.
|
||||
|
||||
type signedData struct {
|
||||
Version int
|
||||
DigestAlgorithms asn1.RawValue
|
||||
ContentInfo asn1.RawValue
|
||||
Certificates asn1.RawValue `asn1:"optional" asn1:"tag:0"`
|
||||
Crls asn1.RawValue `asn1:"optional"`
|
||||
SignerInfos asn1.RawValue
|
||||
}
|
||||
|
||||
type initPKCS7 struct {
|
||||
Raw asn1.RawContent
|
||||
ContentType asn1.ObjectIdentifier
|
||||
Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
|
||||
}
|
||||
|
||||
// Object identifier strings of the three implemented PKCS7 types.
|
||||
const (
|
||||
ObjIDData = "1.2.840.113549.1.7.1"
|
||||
ObjIDSignedData = "1.2.840.113549.1.7.2"
|
||||
ObjIDEncryptedData = "1.2.840.113549.1.7.6"
|
||||
)
|
||||
|
||||
// PKCS7 represents the ASN1 PKCS #7 Content type. It contains one of three
|
||||
// possible types of Content objects, as denoted by the object identifier in
|
||||
// the ContentInfo field, the other two being nil. SignedData
|
||||
// is the degenerate SignedData Content info without signature used
|
||||
// to hold certificates and crls. Data is raw bytes, and EncryptedData
|
||||
// is as defined in PKCS #7 standard.
|
||||
type PKCS7 struct {
|
||||
Raw asn1.RawContent
|
||||
ContentInfo string
|
||||
Content Content
|
||||
}
|
||||
|
||||
// Content implements three of the six possible PKCS7 data types. Only one is non-nil.
|
||||
type Content struct {
|
||||
Data []byte
|
||||
SignedData SignedData
|
||||
EncryptedData EncryptedData
|
||||
}
|
||||
|
||||
// SignedData defines the typical carrier of certificates and crls.
|
||||
type SignedData struct {
|
||||
Raw asn1.RawContent
|
||||
Version int
|
||||
Certificates []*x509.Certificate
|
||||
Crl *pkix.CertificateList
|
||||
}
|
||||
|
||||
// Data contains raw bytes. Used as a subtype in PKCS12.
|
||||
type Data struct {
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
// EncryptedData contains encrypted data. Used as a subtype in PKCS12.
|
||||
type EncryptedData struct {
|
||||
Raw asn1.RawContent
|
||||
Version int
|
||||
EncryptedContentInfo EncryptedContentInfo
|
||||
}
|
||||
|
||||
// EncryptedContentInfo is a subtype of PKCS7EncryptedData.
|
||||
type EncryptedContentInfo struct {
|
||||
Raw asn1.RawContent
|
||||
ContentType asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedContent []byte `asn1:"tag:0,optional"`
|
||||
}
|
||||
|
||||
// ParsePKCS7 attempts to parse the DER encoded bytes of a
|
||||
// PKCS7 structure.
|
||||
func ParsePKCS7(raw []byte) (msg *PKCS7, err error) {
|
||||
|
||||
var pkcs7 initPKCS7
|
||||
_, err = asn1.Unmarshal(raw, &pkcs7)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
|
||||
}
|
||||
|
||||
msg = new(PKCS7)
|
||||
msg.Raw = pkcs7.Raw
|
||||
msg.ContentInfo = pkcs7.ContentType.String()
|
||||
switch {
|
||||
case msg.ContentInfo == ObjIDData:
|
||||
msg.ContentInfo = "Data"
|
||||
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &msg.Content.Data)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
|
||||
}
|
||||
case msg.ContentInfo == ObjIDSignedData:
|
||||
msg.ContentInfo = "SignedData"
|
||||
var signedData signedData
|
||||
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &signedData)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
|
||||
}
|
||||
if len(signedData.Certificates.Bytes) != 0 {
|
||||
msg.Content.SignedData.Certificates, err = x509.ParseCertificates(signedData.Certificates.Bytes)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
|
||||
}
|
||||
}
|
||||
if len(signedData.Crls.Bytes) != 0 {
|
||||
msg.Content.SignedData.Crl, err = x509.ParseDERCRL(signedData.Crls.Bytes)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
|
||||
}
|
||||
}
|
||||
msg.Content.SignedData.Version = signedData.Version
|
||||
msg.Content.SignedData.Raw = pkcs7.Content.Bytes
|
||||
case msg.ContentInfo == ObjIDEncryptedData:
|
||||
msg.ContentInfo = "EncryptedData"
|
||||
var encryptedData EncryptedData
|
||||
_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &encryptedData)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
|
||||
}
|
||||
if encryptedData.Version != 0 {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for PKCS #7 encryptedData version 0"))
|
||||
}
|
||||
msg.Content.EncryptedData = encryptedData
|
||||
|
||||
default:
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Attempt to parse PKCS# 7 Content not of type data, signed data or encrypted data"))
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
|
||||
}
|
432
vendor/github.com/cloudflare/cfssl/csr/csr.go
generated
vendored
Normal file
432
vendor/github.com/cloudflare/cfssl/csr/csr.go
generated
vendored
Normal file
@ -0,0 +1,432 @@
|
||||
// Package csr implements certificate requests for CFSSL.
|
||||
package csr
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"net"
|
||||
"net/mail"
|
||||
"strings"
|
||||
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"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
|
||||
SerialNumber string
|
||||
}
|
||||
|
||||
// A KeyRequest is a generic request for a new key.
|
||||
type KeyRequest interface {
|
||||
Algo() string
|
||||
Size() int
|
||||
Generate() (crypto.PrivateKey, error)
|
||||
SigAlgo() x509.SignatureAlgorithm
|
||||
}
|
||||
|
||||
// A BasicKeyRequest contains the algorithm and key size for a new private key.
|
||||
type BasicKeyRequest struct {
|
||||
A string `json:"algo" yaml:"algo"`
|
||||
S int `json:"size" yaml:"size"`
|
||||
}
|
||||
|
||||
// NewBasicKeyRequest returns a default BasicKeyRequest.
|
||||
func NewBasicKeyRequest() *BasicKeyRequest {
|
||||
return &BasicKeyRequest{"ecdsa", curveP256}
|
||||
}
|
||||
|
||||
// Algo returns the requested key algorithm represented as a string.
|
||||
func (kr *BasicKeyRequest) Algo() string {
|
||||
return kr.A
|
||||
}
|
||||
|
||||
// Size returns the requested key size.
|
||||
func (kr *BasicKeyRequest) Size() int {
|
||||
return kr.S
|
||||
}
|
||||
|
||||
// Generate generates a key as specified in the request. Currently,
|
||||
// only ECDSA and RSA are supported.
|
||||
func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, 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")
|
||||
}
|
||||
if kr.Size() > 8192 {
|
||||
return nil, errors.New("RSA key size too large")
|
||||
}
|
||||
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 *BasicKeyRequest) 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 kr.Size() {
|
||||
case curveP521:
|
||||
return x509.ECDSAWithSHA512
|
||||
case curveP384:
|
||||
return x509.ECDSAWithSHA384
|
||||
case 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" yaml:"pathlen"`
|
||||
PathLenZero bool `json:"pathlenzero" yaml:"pathlenzero"`
|
||||
Expiry string `json:"expiry" yaml:"expiry"`
|
||||
Backdate string `json:"backdate" yaml:"backdate"`
|
||||
}
|
||||
|
||||
// A CertificateRequest encapsulates the API interface to the
|
||||
// certificate request functionality.
|
||||
type CertificateRequest struct {
|
||||
CN string
|
||||
Names []Name `json:"names" yaml:"names"`
|
||||
Hosts []string `json:"hosts" yaml:"hosts"`
|
||||
KeyRequest KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
CA *CAConfig `json:"ca,omitempty" yaml:"ca,omitempty"`
|
||||
SerialNumber string `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
|
||||
}
|
||||
|
||||
// New returns a new, empty CertificateRequest with a
|
||||
// BasicKeyRequest.
|
||||
func New() *CertificateRequest {
|
||||
return &CertificateRequest{
|
||||
KeyRequest: NewBasicKeyRequest(),
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
name.SerialNumber = cr.SerialNumber
|
||||
return name
|
||||
}
|
||||
|
||||
// BasicConstraints CSR information RFC 5280, 4.2.1.9
|
||||
type BasicConstraints struct {
|
||||
IsCA bool `asn1:"optional"`
|
||||
MaxPathLen int `asn1:"optional,default:-1"`
|
||||
}
|
||||
|
||||
// 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 = NewBasicKeyRequest()
|
||||
}
|
||||
|
||||
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.")
|
||||
}
|
||||
|
||||
csr, err = Generate(priv.(crypto.Signer), req)
|
||||
if err != nil {
|
||||
log.Errorf("failed to generate a CSR: %v", err)
|
||||
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ExtractCertificateRequest extracts a CertificateRequest from
|
||||
// x509.Certificate. It is aimed to used for generating a new certificate
|
||||
// from an existing certificate. For a root certificate, the CA expiry
|
||||
// length is calculated as the duration between cert.NotAfter and cert.NotBefore.
|
||||
func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
|
||||
req := New()
|
||||
req.CN = cert.Subject.CommonName
|
||||
req.Names = getNames(cert.Subject)
|
||||
req.Hosts = getHosts(cert)
|
||||
req.SerialNumber = cert.Subject.SerialNumber
|
||||
|
||||
if cert.IsCA {
|
||||
req.CA = new(CAConfig)
|
||||
// CA expiry length is calculated based on the input cert
|
||||
// issue date and expiry date.
|
||||
req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
|
||||
req.CA.PathLength = cert.MaxPathLen
|
||||
req.CA.PathLenZero = cert.MaxPathLenZero
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
func getHosts(cert *x509.Certificate) []string {
|
||||
var hosts []string
|
||||
for _, ip := range cert.IPAddresses {
|
||||
hosts = append(hosts, ip.String())
|
||||
}
|
||||
for _, dns := range cert.DNSNames {
|
||||
hosts = append(hosts, dns)
|
||||
}
|
||||
for _, email := range cert.EmailAddresses {
|
||||
hosts = append(hosts, email)
|
||||
}
|
||||
|
||||
return hosts
|
||||
}
|
||||
|
||||
// getNames returns an array of Names from the certificate
|
||||
// It onnly cares about Country, Organization, OrganizationalUnit, Locality, Province
|
||||
func getNames(sub pkix.Name) []Name {
|
||||
// anonymous func for finding the max of a list of interger
|
||||
max := func(v1 int, vn ...int) (max int) {
|
||||
max = v1
|
||||
for i := 0; i < len(vn); i++ {
|
||||
if vn[i] > max {
|
||||
max = vn[i]
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
nc := len(sub.Country)
|
||||
norg := len(sub.Organization)
|
||||
nou := len(sub.OrganizationalUnit)
|
||||
nl := len(sub.Locality)
|
||||
np := len(sub.Province)
|
||||
|
||||
n := max(nc, norg, nou, nl, np)
|
||||
|
||||
names := make([]Name, n)
|
||||
for i := range names {
|
||||
if i < nc {
|
||||
names[i].C = sub.Country[i]
|
||||
}
|
||||
if i < norg {
|
||||
names[i].O = sub.Organization[i]
|
||||
}
|
||||
if i < nou {
|
||||
names[i].OU = sub.OrganizationalUnit[i]
|
||||
}
|
||||
if i < nl {
|
||||
names[i].L = sub.Locality[i]
|
||||
}
|
||||
if i < np {
|
||||
names[i].ST = sub.Province[i]
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// 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 nil, nil, err
|
||||
}
|
||||
|
||||
csr, key, err = ParseRequest(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// IsNameEmpty returns true if the name has no identifying information in it.
|
||||
func IsNameEmpty(n Name) bool {
|
||||
empty := func(s string) bool { return strings.TrimSpace(s) == "" }
|
||||
|
||||
if empty(n.C) && empty(n.ST) && empty(n.L) && empty(n.O) && empty(n.OU) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Regenerate uses the provided CSR as a template for signing a new
|
||||
// CSR using priv.
|
||||
func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
|
||||
req, extra, err := helpers.ParseCSR(csr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(extra) > 0 {
|
||||
return nil, errors.New("csr: trailing data in certificate request")
|
||||
}
|
||||
|
||||
return x509.CreateCertificateRequest(rand.Reader, req, priv)
|
||||
}
|
||||
|
||||
// Generate creates a new CSR from a CertificateRequest structure and
|
||||
// an existing key. The KeyRequest field is ignored.
|
||||
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
|
||||
sigAlgo := helpers.SignerAlgo(priv)
|
||||
if sigAlgo == x509.UnknownSignatureAlgorithm {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
|
||||
}
|
||||
|
||||
var tpl = x509.CertificateRequest{
|
||||
Subject: req.Name(),
|
||||
SignatureAlgorithm: sigAlgo,
|
||||
}
|
||||
|
||||
for i := range req.Hosts {
|
||||
if ip := net.ParseIP(req.Hosts[i]); ip != nil {
|
||||
tpl.IPAddresses = append(tpl.IPAddresses, ip)
|
||||
} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
|
||||
tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
|
||||
} else {
|
||||
tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
|
||||
}
|
||||
}
|
||||
|
||||
if req.CA != nil {
|
||||
err = appendCAInfoToCSR(req.CA, &tpl)
|
||||
if err != nil {
|
||||
err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
|
||||
if err != nil {
|
||||
log.Errorf("failed to generate a CSR: %v", err)
|
||||
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
|
||||
return
|
||||
}
|
||||
block := pem.Block{
|
||||
Type: "CERTIFICATE REQUEST",
|
||||
Bytes: csr,
|
||||
}
|
||||
|
||||
log.Info("encoded CSR")
|
||||
csr = pem.EncodeToMemory(&block)
|
||||
return
|
||||
}
|
||||
|
||||
// appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
|
||||
func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
|
||||
pathlen := reqConf.PathLength
|
||||
if pathlen == 0 && !reqConf.PathLenZero {
|
||||
pathlen = -1
|
||||
}
|
||||
val, err := asn1.Marshal(BasicConstraints{true, pathlen})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
csr.ExtraExtensions = []pkix.Extension{
|
||||
{
|
||||
Id: asn1.ObjectIdentifier{2, 5, 29, 19},
|
||||
Value: val,
|
||||
Critical: true,
|
||||
},
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
744
vendor/github.com/cloudflare/cfssl/csr/csr_test.go
generated
vendored
Normal file
744
vendor/github.com/cloudflare/cfssl/csr/csr_test.go
generated
vendored
Normal file
@ -0,0 +1,744 @@
|
||||
package csr
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
)
|
||||
|
||||
//TestNew validate the CertificateRequest created to return with a BasicKeyRequest
|
||||
//in KeyRequest field
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
if cr := New(); cr.KeyRequest == nil {
|
||||
t.Fatalf("Should create a new, empty certificate request with BasicKeyRequest")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBasicKeyRequest ensures that key generation returns the same type of
|
||||
// key specified in the BasicKeyRequest.
|
||||
func TestBasicKeyRequest(t *testing.T) {
|
||||
kr := NewBasicKeyRequest()
|
||||
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 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: NewBasicKeyRequest(),
|
||||
}
|
||||
|
||||
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 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", "192.168.0.1", "jdoe@example.com"},
|
||||
KeyRequest: NewBasicKeyRequest(),
|
||||
}
|
||||
|
||||
_, _, err := ParseRequest(cr)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseRequestCA ensures that a valid CA certificate request does not
|
||||
// error and the resulting CSR includes the BasicConstraint extension
|
||||
func TestParseRequestCA(t *testing.T) {
|
||||
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",
|
||||
},
|
||||
},
|
||||
CA: &CAConfig{
|
||||
PathLength: 0,
|
||||
PathLenZero: true,
|
||||
},
|
||||
KeyRequest: NewBasicKeyRequest(),
|
||||
}
|
||||
|
||||
csrBytes, _, err := ParseRequest(cr)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(csrBytes)
|
||||
if block == nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if block.Type != "CERTIFICATE REQUEST" {
|
||||
t.Fatalf("Incorrect block type: %s", block.Type)
|
||||
}
|
||||
|
||||
csr, err := x509.ParseCertificateRequest(block.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, ext := range csr.Extensions {
|
||||
if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("CSR did not include BasicConstraint Extension")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseRequestCANoPathlen ensures that a valid CA certificate request
|
||||
// with an unspecified pathlen does not error and the resulting CSR includes
|
||||
// the BasicConstraint extension
|
||||
func TestParseRequestCANoPathlen(t *testing.T) {
|
||||
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",
|
||||
},
|
||||
},
|
||||
CA: &CAConfig{
|
||||
PathLength: 0,
|
||||
PathLenZero: false,
|
||||
},
|
||||
KeyRequest: NewBasicKeyRequest(),
|
||||
}
|
||||
|
||||
csrBytes, _, err := ParseRequest(cr)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(csrBytes)
|
||||
if block == nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if block.Type != "CERTIFICATE REQUEST" {
|
||||
t.Fatalf("Incorrect block type: %s", block.Type)
|
||||
}
|
||||
|
||||
csr, err := x509.ParseCertificateRequest(block.Bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, ext := range csr.Extensions {
|
||||
if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
|
||||
bc := &BasicConstraints{}
|
||||
asn1.Unmarshal(ext.Value, bc)
|
||||
if bc.IsCA == true && bc.MaxPathLen == -1 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("CSR did not include BasicConstraint Extension")
|
||||
}
|
||||
}
|
||||
|
||||
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 := &BasicKeyRequest{"ecdsa", 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 := &BasicKeyRequest{"rsa", 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!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestBadBasicKeyRequest ensures that generating a key from a BasicKeyRequest
|
||||
// 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 TestBadBasicKeyRequest(t *testing.T) {
|
||||
kr := &BasicKeyRequest{"yolocrypto", 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.A = "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.A = "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!")
|
||||
}
|
||||
|
||||
kr = &BasicKeyRequest{"tobig", 9216}
|
||||
|
||||
kr.A = "rsa"
|
||||
if _, err := kr.Generate(); err == nil {
|
||||
t.Fatal("Key generation should fail with invalid key size")
|
||||
} else if sa := kr.SigAlgo(); sa != x509.SHA512WithRSA {
|
||||
t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDefaultBasicKeyRequest makes sure that certificate requests without
|
||||
// explicit key requests fall back to the default key request.
|
||||
func TestDefaultBasicKeyRequest(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", "jdoe@example.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!")
|
||||
}
|
||||
|
||||
DefaultKeyRequest := NewBasicKeyRequest()
|
||||
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", "jdoe@example.com"},
|
||||
KeyRequest: &BasicKeyRequest{"rsa", 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: &BasicKeyRequest{"yolo-crypto", 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", "192.168.0.1", "jdoe@example.com"},
|
||||
KeyRequest: &BasicKeyRequest{"rsa", 2048},
|
||||
}
|
||||
|
||||
csrBytes, _, err := g.ProcessRequest(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode([]byte(csrBytes))
|
||||
if block == nil {
|
||||
t.Fatalf("bad CSR in PEM")
|
||||
}
|
||||
|
||||
if block.Type != "CERTIFICATE REQUEST" {
|
||||
t.Fatalf("bad CSR in PEM")
|
||||
}
|
||||
|
||||
csr, err := x509.ParseCertificateRequest(block.Bytes)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(csr.DNSNames) != 2 {
|
||||
t.Fatal("SAN parsing error")
|
||||
}
|
||||
|
||||
if len(csr.IPAddresses) != 1 {
|
||||
t.Fatal("SAN parsing error")
|
||||
}
|
||||
|
||||
if len(csr.EmailAddresses) != 1 {
|
||||
t.Fatal("SAN parsing error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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: &BasicKeyRequest{"rsa", 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", "jdoe@example.com"},
|
||||
KeyRequest: &BasicKeyRequest{"rsa", 1024},
|
||||
}
|
||||
g := &Generator{testValidator}
|
||||
|
||||
_, _, err := g.ProcessRequest(weakKey)
|
||||
if err == nil {
|
||||
t.Fatalf("Request should have failed.")
|
||||
}
|
||||
}
|
||||
|
||||
var testEmpty = []struct {
|
||||
name Name
|
||||
ok bool
|
||||
}{
|
||||
{
|
||||
Name{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
Name{C: "OK"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
Name{ST: "OK"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
Name{L: "OK"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
Name{O: "OK"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
Name{OU: "OK"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestIsNameEmpty(t *testing.T) {
|
||||
for i, c := range testEmpty {
|
||||
if IsNameEmpty(c.name) != c.ok {
|
||||
t.Fatalf("%d: expected IsNameEmpty to return %v, but have %v", i, c.ok, !c.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerate(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", "192.168.0.1", "jdoe@example.com"},
|
||||
KeyRequest: &BasicKeyRequest{"ecdsa", 256},
|
||||
}
|
||||
|
||||
key, err := req.KeyRequest.Generate()
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
priv, ok := key.(crypto.Signer)
|
||||
if !ok {
|
||||
t.Fatal("Private key is not a signer.")
|
||||
}
|
||||
|
||||
csrPEM, err := Generate(priv, req)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
csr, _, err := helpers.ParseCSR(csrPEM)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if len(csr.DNSNames) != 2 {
|
||||
t.Fatal("SAN parsing error")
|
||||
}
|
||||
|
||||
if len(csr.IPAddresses) != 1 {
|
||||
t.Fatal("SAN parsing error")
|
||||
}
|
||||
|
||||
if len(csr.EmailAddresses) != 1 {
|
||||
t.Fatal("SAN parsing error")
|
||||
}
|
||||
}
|
||||
|
||||
// TestReGenerate ensures Regenerate() is abel to use the provided CSR as a template for signing a new
|
||||
// CSR using priv.
|
||||
func TestReGenerate(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", "192.168.0.1"},
|
||||
KeyRequest: &BasicKeyRequest{"ecdsa", 256},
|
||||
}
|
||||
|
||||
_, key, err := ParseRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(key)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
csr, err := Generate(priv, req)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if _, _, err = helpers.ParseCSR(csr); err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
_, err = Regenerate(priv, csr)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestBadReGenerator ensures that a request that fails the ParseCSR is
|
||||
// not processed.
|
||||
func TestBadReGenerate(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", "192.168.0.1"},
|
||||
KeyRequest: &BasicKeyRequest{"ecdsa", 256},
|
||||
}
|
||||
|
||||
_, key, err := ParseRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(key)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
csr, err := Generate(priv, req)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
block := pem.Block{
|
||||
Type: "CERTIFICATE REQUEST",
|
||||
Headers: map[string]string{
|
||||
"Location": "UCSD",
|
||||
},
|
||||
Bytes: csr,
|
||||
}
|
||||
|
||||
csr = pem.EncodeToMemory(&block)
|
||||
|
||||
_, err = Regenerate(priv, csr)
|
||||
if err == nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var testECDSACertificateFile = "testdata/test-ecdsa-ca.pem"
|
||||
|
||||
func TestExtractCertificateRequest(t *testing.T) {
|
||||
certPEM, err := ioutil.ReadFile(testECDSACertificateFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// must parse ok
|
||||
cert, err := helpers.ParseCertificatePEM(certPEM)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req := ExtractCertificateRequest(cert)
|
||||
|
||||
if req.CN != "" {
|
||||
t.Fatal("Bad Certificate Request!")
|
||||
}
|
||||
|
||||
if len(req.Names) != 1 {
|
||||
t.Fatal("Bad Certificate Request!")
|
||||
}
|
||||
|
||||
name := req.Names[0]
|
||||
if name.C != "US" || name.ST != "California" || name.O != "CloudFlare, Inc." ||
|
||||
name.OU != "Test Certificate Authority" || name.L != "San Francisco" {
|
||||
t.Fatal("Bad Certificate Request!")
|
||||
}
|
||||
|
||||
if req.CA == nil || req.CA.PathLength != 2 {
|
||||
t.Fatal("Bad Certificate Request!")
|
||||
}
|
||||
}
|
15
vendor/github.com/cloudflare/cfssl/csr/testdata/test-ecdsa-ca.pem
generated
vendored
Normal file
15
vendor/github.com/cloudflare/cfssl/csr/testdata/test-ecdsa-ca.pem
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICUDCCAfagAwIBAgIIec5PjdpJcNYwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMC
|
||||
VVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3QgQ2Vy
|
||||
dGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD
|
||||
VQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIzMDEwMFoXDTE1MTAwODIzMDYwMFow
|
||||
ejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNV
|
||||
BAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJh
|
||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||
AQcDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI7Lzf
|
||||
GbMU+KqWTgOwGhrPvpusep3fjw+dAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud
|
||||
EwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFDpLhSKBN3njfb6cXQCdRLzCZt0ZMB8G
|
||||
A1UdIwQYMBaAFDpLhSKBN3njfb6cXQCdRLzCZt0ZMAoGCCqGSM49BAMCA0gAMEUC
|
||||
IFU3BmzntGGeXZu2qWZx249nYn37S0AkCnQ3rUtI31bdAiEAsPICnZ+GB8yCN26N
|
||||
OL+N8dHvXiOvZ9/Vl488pyWOccY=
|
||||
-----END CERTIFICATE-----
|
46
vendor/github.com/cloudflare/cfssl/errors/doc.go
generated
vendored
Normal file
46
vendor/github.com/cloudflare/cfssl/errors/doc.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
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
|
||||
5400: UnknownProfile
|
||||
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
|
438
vendor/github.com/cloudflare/cfssl/errors/error.go
generated
vendored
Normal file
438
vendor/github.com/cloudflare/cfssl/errors/error.go
generated
vendored
Normal file
@ -0,0 +1,438 @@
|
||||
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
|
||||
|
||||
// CSRError indicates a problem with CSR parsing
|
||||
CSRError // 9XXX
|
||||
|
||||
// CTError indicates a problem with the certificate transparency process
|
||||
CTError // 10XXX
|
||||
|
||||
// CertStoreError indicates a problem with the certificate store
|
||||
CertStoreError // 11XXX
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
// MissingSerial indicates that the profile specified
|
||||
// 'ClientProvidesSerialNumbers', but the SignRequest did not include a serial
|
||||
// number.
|
||||
MissingSerial // Code 14XX
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
// UnknownProfile indicates that the profile does not exist.
|
||||
UnknownProfile // 54XX
|
||||
|
||||
UnmatchedWhitelist // 55xx
|
||||
)
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// Certificate transparency related errors specified with CTError
|
||||
const (
|
||||
// PrecertSubmissionFailed occurs when submitting a precertificate to
|
||||
// a log server fails
|
||||
PrecertSubmissionFailed = 100 * (iota + 1)
|
||||
// CTClientConstructionFailed occurs when the construction of a new
|
||||
// github.com/google/certificate-transparency client fails.
|
||||
CTClientConstructionFailed
|
||||
// PrecertMissingPoison occurs when a precert is passed to SignFromPrecert
|
||||
// and is missing the CT poison extension.
|
||||
PrecertMissingPoison
|
||||
// PrecertInvalidPoison occurs when a precert is passed to SignFromPrecert
|
||||
// and has a invalid CT poison extension value or the extension is not
|
||||
// critical.
|
||||
PrecertInvalidPoison
|
||||
)
|
||||
|
||||
// Certificate persistence related errors specified with CertStoreError
|
||||
const (
|
||||
// InsertionFailed occurs when a SQL insert query failes to complete.
|
||||
InsertionFailed = 100 * (iota + 1)
|
||||
// RecordNotFound occurs when a SQL query targeting on one unique
|
||||
// record failes to update the specified row in the table.
|
||||
RecordNotFound
|
||||
)
|
||||
|
||||
// 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"
|
||||
case MissingSerial:
|
||||
msg = "Missing serial number in request"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL 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 CFSSL 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 CFSSL 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 CFSSL 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"
|
||||
case UnknownProfile:
|
||||
msg = "Unknown policy profile"
|
||||
case UnmatchedWhitelist:
|
||||
msg = "Request does not match policy whitelist"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error reason %d under category PolicyError.",
|
||||
reason))
|
||||
}
|
||||
case DialError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Failed to dial remote server"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL 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 CFSSL error reason %d under category APIClientError.",
|
||||
reason))
|
||||
}
|
||||
case CSRError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "CSR parsing failed due to unknown error"
|
||||
case ReadFailed:
|
||||
msg = "CSR file read failed"
|
||||
case ParseFailed:
|
||||
msg = "CSR Parsing failed"
|
||||
case DecodeFailed:
|
||||
msg = "CSR Decode failed"
|
||||
case BadRequest:
|
||||
msg = "CSR Bad request"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category APIClientError.", reason))
|
||||
}
|
||||
case CTError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Certificate transparency parsing failed due to unknown error"
|
||||
case PrecertSubmissionFailed:
|
||||
msg = "Certificate transparency precertificate submission failed"
|
||||
case PrecertMissingPoison:
|
||||
msg = "Precertificate is missing CT poison extension"
|
||||
case PrecertInvalidPoison:
|
||||
msg = "Precertificate contains an invalid CT poison extension"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CTError.", reason))
|
||||
}
|
||||
case CertStoreError:
|
||||
switch reason {
|
||||
case Unknown:
|
||||
msg = "Certificate store action failed due to unknown error"
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CF-SSL error reason %d under category CertStoreError.", reason))
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL 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, CSRError, CTError, CertStoreError, OCSPError:
|
||||
// no-op, just use the error
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported CFSSL error type: %d.",
|
||||
category))
|
||||
}
|
||||
|
||||
return &Error{ErrorCode: errorCode, Message: err.Error()}
|
||||
|
||||
}
|
338
vendor/github.com/cloudflare/cfssl/errors/error_test.go
generated
vendored
Normal file
338
vendor/github.com/cloudflare/cfssl/errors/error_test.go
generated
vendored
Normal file
@ -0,0 +1,338 @@
|
||||
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.")
|
||||
}
|
||||
|
||||
code := New(OCSPError, ReadFailed).ErrorCode
|
||||
if code != 8001 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(OCSPError, IssuerMismatch).ErrorCode
|
||||
if code != 8100 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(OCSPError, InvalidStatus).ErrorCode
|
||||
if code != 8200 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(CertificateError, Unknown).ErrorCode
|
||||
if code != 1000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CertificateError, ReadFailed).ErrorCode
|
||||
if code != 1001 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CertificateError, DecodeFailed).ErrorCode
|
||||
if code != 1002 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CertificateError, ParseFailed).ErrorCode
|
||||
if code != 1003 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CertificateError, SelfSigned).ErrorCode
|
||||
if code != 1100 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CertificateError, VerifyFailed).ErrorCode
|
||||
if code != 1200 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CertificateError, BadRequest).ErrorCode
|
||||
if code != 1300 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CertificateError, MissingSerial).ErrorCode
|
||||
if code != 1400 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(PrivateKeyError, Unknown).ErrorCode
|
||||
if code != 2000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, ReadFailed).ErrorCode
|
||||
if code != 2001 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, DecodeFailed).ErrorCode
|
||||
if code != 2002 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, ParseFailed).ErrorCode
|
||||
if code != 2003 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, Encrypted).ErrorCode
|
||||
if code != 2100 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, NotRSAOrECC).ErrorCode
|
||||
if code != 2200 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, KeyMismatch).ErrorCode
|
||||
if code != 2300 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, GenerationFailed).ErrorCode
|
||||
if code != 2400 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PrivateKeyError, Unavailable).ErrorCode
|
||||
if code != 2500 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(IntermediatesError, Unknown).ErrorCode
|
||||
if code != 3000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(IntermediatesError, ReadFailed).ErrorCode
|
||||
if code != 3001 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(IntermediatesError, DecodeFailed).ErrorCode
|
||||
if code != 3002 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(IntermediatesError, ParseFailed).ErrorCode
|
||||
if code != 3003 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(RootError, Unknown).ErrorCode
|
||||
if code != 4000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(RootError, ReadFailed).ErrorCode
|
||||
if code != 4001 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(RootError, DecodeFailed).ErrorCode
|
||||
if code != 4002 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(RootError, ParseFailed).ErrorCode
|
||||
if code != 4003 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(PolicyError, Unknown).ErrorCode
|
||||
if code != 5000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PolicyError, NoKeyUsages).ErrorCode
|
||||
if code != 5100 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PolicyError, InvalidPolicy).ErrorCode
|
||||
if code != 5200 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PolicyError, InvalidRequest).ErrorCode
|
||||
if code != 5300 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(PolicyError, UnknownProfile).ErrorCode
|
||||
if code != 5400 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(DialError, Unknown).ErrorCode
|
||||
if code != 6000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(APIClientError, AuthenticationFailure).ErrorCode
|
||||
if code != 7100 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(APIClientError, JSONError).ErrorCode
|
||||
if code != 7200 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(APIClientError, ClientHTTPError).ErrorCode
|
||||
if code != 7400 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(APIClientError, IOError).ErrorCode
|
||||
if code != 7300 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(APIClientError, ServerRequestFailed).ErrorCode
|
||||
if code != 7500 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(CSRError, Unknown).ErrorCode
|
||||
if code != 9000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CSRError, ReadFailed).ErrorCode
|
||||
if code != 9001 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CSRError, DecodeFailed).ErrorCode
|
||||
if code != 9002 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CSRError, ParseFailed).ErrorCode
|
||||
if code != 9003 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CSRError, KeyMismatch).ErrorCode
|
||||
if code != 9300 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CSRError, BadRequest).ErrorCode
|
||||
if code != 9300 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
|
||||
code = New(CTError, Unknown).ErrorCode
|
||||
if code != 10000 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
code = New(CTError, PrecertSubmissionFailed).ErrorCode
|
||||
if code != 10100 {
|
||||
t.Fatal("Improper error code")
|
||||
}
|
||||
}
|
||||
|
||||
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.")
|
||||
}
|
||||
|
||||
err = Wrap(CertificateError, VerifyFailed, x509.UnknownAuthorityError{})
|
||||
if err == nil {
|
||||
t.Fatal("Error creation failed.")
|
||||
}
|
||||
|
||||
err = Wrap(RootError, Unknown, errors.New(msg))
|
||||
if err == nil {
|
||||
t.Fatal("Error creation failed.")
|
||||
}
|
||||
if err.ErrorCode != int(RootError)+int(Unknown) {
|
||||
t.Fatal("Error code construction failed.")
|
||||
}
|
||||
if err.Message != msg {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTP(t *testing.T) {
|
||||
err := NewMethodNotAllowed("GET")
|
||||
if err == nil {
|
||||
t.Fatal("New Mathod Check failed")
|
||||
}
|
||||
|
||||
err = NewBadRequest(errors.New("Bad Request"))
|
||||
if err == nil {
|
||||
t.Fatal("New Bad Request Check failed")
|
||||
}
|
||||
|
||||
if err.StatusCode != 400 {
|
||||
t.Fatal("New Bad Request error code construction failed")
|
||||
}
|
||||
|
||||
err = NewBadRequestString("Bad Request String")
|
||||
if err == nil {
|
||||
t.Fatal("New Bad Request String Check failed")
|
||||
}
|
||||
|
||||
if err.StatusCode != 400 {
|
||||
t.Fatal("New Bad Request String error code construction failed")
|
||||
}
|
||||
|
||||
err = NewBadRequestMissingParameter("Request Missing Parameter")
|
||||
if err == nil {
|
||||
t.Fatal("New Bad Request Missing Parameter Check failed")
|
||||
}
|
||||
|
||||
if err.StatusCode != 400 {
|
||||
t.Fatal("New Bad Request Missing Parameter error code construction failed")
|
||||
}
|
||||
|
||||
err = NewBadRequestUnwantedParameter("Unwanted Parameter Present In Request")
|
||||
if err == nil {
|
||||
t.Fatal("New Bad Request Unwanted Parameter Check failed")
|
||||
}
|
||||
|
||||
if err.StatusCode != 400 {
|
||||
t.Fatal("New Bad Request Unwanted Parameter error code construction failed")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestHTTPErrorString(t *testing.T) {
|
||||
method := "GET"
|
||||
err := NewMethodNotAllowed(method)
|
||||
str := err.Error()
|
||||
if str != `Method is not allowed:"`+method+`"` {
|
||||
t.Fatal("Incorrect Error():", str)
|
||||
}
|
||||
}
|
47
vendor/github.com/cloudflare/cfssl/errors/http.go
generated
vendored
Normal file
47
vendor/github.com/cloudflare/cfssl/errors/http.go
generated
vendored
Normal file
@ -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 + `"`)
|
||||
}
|
42
vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go
generated
vendored
Normal file
42
vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
// Package derhelpers implements common functionality
|
||||
// on DER encoded data
|
||||
package derhelpers
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// should never reach here
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed)
|
||||
}
|
577
vendor/github.com/cloudflare/cfssl/helpers/helpers.go
generated
vendored
Normal file
577
vendor/github.com/cloudflare/cfssl/helpers/helpers.go
generated
vendored
Normal file
@ -0,0 +1,577 @@
|
||||
// Package helpers implements utility functionality common to many
|
||||
// CFSSL packages.
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/google/certificate-transparency-go"
|
||||
cttls "github.com/google/certificate-transparency-go/tls"
|
||||
ctx509 "github.com/google/certificate-transparency-go/x509"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/crypto/pkcs7"
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers/derhelpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"golang.org/x/crypto/pkcs12"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
// InclusiveDate returns the time.Time representation of a date - 1
|
||||
// nanosecond. This allows time.After to be used inclusively.
|
||||
func InclusiveDate(year int, month time.Month, day int) time.Time {
|
||||
return time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Add(-1 * time.Nanosecond)
|
||||
}
|
||||
|
||||
// Jul2012 is the July 2012 CAB Forum deadline for when CAs must stop
|
||||
// issuing certificates valid for more than 5 years.
|
||||
var Jul2012 = InclusiveDate(2012, time.July, 01)
|
||||
|
||||
// Apr2015 is the April 2015 CAB Forum deadline for when CAs must stop
|
||||
// issuing certificates valid for more than 39 months.
|
||||
var Apr2015 = InclusiveDate(2015, time.April, 01)
|
||||
|
||||
// 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) (notAfter time.Time) {
|
||||
if len(chain) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
notAfter = chain[0].NotAfter
|
||||
for _, cert := range chain {
|
||||
if notAfter.After(cert.NotAfter) {
|
||||
notAfter = cert.NotAfter
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MonthsValid returns the number of months for which a certificate is valid.
|
||||
func MonthsValid(c *x509.Certificate) int {
|
||||
issued := c.NotBefore
|
||||
expiry := c.NotAfter
|
||||
years := (expiry.Year() - issued.Year())
|
||||
months := years*12 + int(expiry.Month()) - int(issued.Month())
|
||||
|
||||
// Round up if valid for less than a full month
|
||||
if expiry.Day() > issued.Day() {
|
||||
months++
|
||||
}
|
||||
return months
|
||||
}
|
||||
|
||||
// ValidExpiry determines if a certificate is valid for an acceptable
|
||||
// length of time per the CA/Browser Forum baseline requirements.
|
||||
// See https://cabforum.org/wp-content/uploads/CAB-Forum-BR-1.3.0.pdf
|
||||
func ValidExpiry(c *x509.Certificate) bool {
|
||||
issued := c.NotBefore
|
||||
|
||||
var maxMonths int
|
||||
switch {
|
||||
case issued.After(Apr2015):
|
||||
maxMonths = 39
|
||||
case issued.After(Jul2012):
|
||||
maxMonths = 60
|
||||
case issued.Before(Jul2012):
|
||||
maxMonths = 120
|
||||
}
|
||||
|
||||
if MonthsValid(c) > maxMonths {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 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"
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeCertificatesPEM encodes a number of x509 certificates to PEM
|
||||
func EncodeCertificatesPEM(certs []*x509.Certificate) []byte {
|
||||
var buffer bytes.Buffer
|
||||
for _, cert := range certs {
|
||||
pem.Encode(&buffer, &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: cert.Raw,
|
||||
})
|
||||
}
|
||||
|
||||
return buffer.Bytes()
|
||||
}
|
||||
|
||||
// EncodeCertificatePEM encodes a single x509 certificates to PEM
|
||||
func EncodeCertificatePEM(cert *x509.Certificate) []byte {
|
||||
return EncodeCertificatesPEM([]*x509.Certificate{cert})
|
||||
}
|
||||
|
||||
// ParseCertificatesPEM parses a sequence of PEM-encoded certificate and returns them,
|
||||
// can handle PEM encoded PKCS #7 structures.
|
||||
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
|
||||
}
|
||||
|
||||
// ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key,
|
||||
// either PKCS #7, PKCS #12, or raw x509.
|
||||
func ParseCertificatesDER(certsDER []byte, password string) (certs []*x509.Certificate, key crypto.Signer, err error) {
|
||||
certsDER = bytes.TrimSpace(certsDER)
|
||||
pkcs7data, err := pkcs7.ParsePKCS7(certsDER)
|
||||
if err != nil {
|
||||
var pkcs12data interface{}
|
||||
certs = make([]*x509.Certificate, 1)
|
||||
pkcs12data, certs[0], err = pkcs12.Decode(certsDER, password)
|
||||
if err != nil {
|
||||
certs, err = x509.ParseCertificates(certsDER)
|
||||
if err != nil {
|
||||
return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
|
||||
}
|
||||
} else {
|
||||
key = pkcs12data.(crypto.Signer)
|
||||
}
|
||||
} else {
|
||||
if pkcs7data.ContentInfo != "SignedData" {
|
||||
return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info"))
|
||||
}
|
||||
certs = pkcs7data.Content.SignedData.Certificates
|
||||
}
|
||||
if certs == nil {
|
||||
return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
|
||||
}
|
||||
return certs, key, 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,
|
||||
// can handle PEM encoded PKCS #7 structures.
|
||||
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 object"))
|
||||
} else if len(cert) > 1 {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate"))
|
||||
}
|
||||
return cert[0], nil
|
||||
}
|
||||
|
||||
// ParseOneCertificateFromPEM attempts to parse one PEM encoded certificate object,
|
||||
// either a raw x509 certificate or a PKCS #7 structure possibly containing
|
||||
// multiple certificates, from the top of certsPEM, which itself may
|
||||
// contain multiple PEM encoded certificate objects.
|
||||
func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, error) {
|
||||
|
||||
block, rest := pem.Decode(certsPEM)
|
||||
if block == nil {
|
||||
return nil, rest, nil
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
pkcs7data, err := pkcs7.ParsePKCS7(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, rest, err
|
||||
}
|
||||
if pkcs7data.ContentInfo != "SignedData" {
|
||||
return nil, rest, errors.New("only PKCS #7 Signed Data Content Info supported for certificate parsing")
|
||||
}
|
||||
certs := pkcs7data.Content.SignedData.Certificates
|
||||
if certs == nil {
|
||||
return nil, rest, errors.New("PKCS #7 structure contains no certificates")
|
||||
}
|
||||
return certs, rest, nil
|
||||
}
|
||||
var certs = []*x509.Certificate{cert}
|
||||
return certs, rest, nil
|
||||
}
|
||||
|
||||
// LoadPEMCertPool loads a pool of PEM certificates from file.
|
||||
func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
|
||||
if certsFile == "" {
|
||||
return nil, nil
|
||||
}
|
||||
pemCerts, err := ioutil.ReadFile(certsFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return PEMToCertPool(pemCerts)
|
||||
}
|
||||
|
||||
// PEMToCertPool concerts PEM certificates to a CertPool.
|
||||
func PEMToCertPool(pemCerts []byte) (*x509.CertPool, error) {
|
||||
if len(pemCerts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
certPool := x509.NewCertPool()
|
||||
if !certPool.AppendCertsFromPEM(pemCerts) {
|
||||
return nil, errors.New("failed to load cert pool")
|
||||
}
|
||||
|
||||
return certPool, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return ParsePrivateKeyPEMWithPassword(keyPEM, nil)
|
||||
}
|
||||
|
||||
// ParsePrivateKeyPEMWithPassword parses and returns a PEM-encoded private
|
||||
// key. The private key may be a potentially encrypted PKCS#8, PKCS#1,
|
||||
// or elliptic private key.
|
||||
func ParsePrivateKeyPEMWithPassword(keyPEM []byte, password []byte) (key crypto.Signer, err error) {
|
||||
keyDER, err := GetKeyDERFromPEM(keyPEM, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return derhelpers.ParsePrivateKeyDER(keyDER)
|
||||
}
|
||||
|
||||
// GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes.
|
||||
func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) {
|
||||
keyDER, _ := pem.Decode(in)
|
||||
if keyDER != nil {
|
||||
if procType, ok := keyDER.Headers["Proc-Type"]; ok {
|
||||
if strings.Contains(procType, "ENCRYPTED") {
|
||||
if password != nil {
|
||||
return x509.DecryptPEMBlock(keyDER, password)
|
||||
}
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted)
|
||||
}
|
||||
}
|
||||
return keyDER.Bytes, nil
|
||||
}
|
||||
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
|
||||
}
|
||||
|
||||
// ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request.
|
||||
func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) {
|
||||
in = bytes.TrimSpace(in)
|
||||
p, rest := pem.Decode(in)
|
||||
if p != nil {
|
||||
if p.Type != "NEW CERTIFICATE REQUEST" && p.Type != "CERTIFICATE REQUEST" {
|
||||
return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest)
|
||||
}
|
||||
|
||||
csr, err = x509.ParseCertificateRequest(p.Bytes)
|
||||
} else {
|
||||
csr, err = x509.ParseCertificateRequest(in)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, rest, err
|
||||
}
|
||||
|
||||
err = csr.CheckSignature()
|
||||
if err != nil {
|
||||
return nil, rest, err
|
||||
}
|
||||
|
||||
return csr, rest, nil
|
||||
}
|
||||
|
||||
// ParseCSRPEM parses a PEM-encoded certificate signing request.
|
||||
// It does not check the signature. This is useful for dumping data from a CSR
|
||||
// locally.
|
||||
func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
|
||||
block, _ := pem.Decode([]byte(csrPEM))
|
||||
if block == nil {
|
||||
return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
|
||||
}
|
||||
csrObject, err := x509.ParseCertificateRequest(block.Bytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return csrObject, nil
|
||||
}
|
||||
|
||||
// SignerAlgo returns an X.509 signature algorithm from a crypto.Signer.
|
||||
func SignerAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
|
||||
switch pub := priv.Public().(type) {
|
||||
case *rsa.PublicKey:
|
||||
bitLength := pub.N.BitLen()
|
||||
switch {
|
||||
case bitLength >= 4096:
|
||||
return x509.SHA512WithRSA
|
||||
case bitLength >= 3072:
|
||||
return x509.SHA384WithRSA
|
||||
case bitLength >= 2048:
|
||||
return x509.SHA256WithRSA
|
||||
default:
|
||||
return x509.SHA1WithRSA
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
switch pub.Curve {
|
||||
case elliptic.P521():
|
||||
return x509.ECDSAWithSHA512
|
||||
case elliptic.P384():
|
||||
return x509.ECDSAWithSHA384
|
||||
case elliptic.P256():
|
||||
return x509.ECDSAWithSHA256
|
||||
default:
|
||||
return x509.ECDSAWithSHA1
|
||||
}
|
||||
default:
|
||||
return x509.UnknownSignatureAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
// LoadClientCertificate load key/certificate from pem files
|
||||
func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, error) {
|
||||
if certFile != "" && keyFile != "" {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
log.Critical("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Client certificate loaded ")
|
||||
return &cert, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CreateTLSConfig creates a tls.Config object from certs and roots
|
||||
func CreateTLSConfig(remoteCAs *x509.CertPool, cert *tls.Certificate) *tls.Config {
|
||||
var certs []tls.Certificate
|
||||
if cert != nil {
|
||||
certs = []tls.Certificate{*cert}
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: certs,
|
||||
RootCAs: remoteCAs,
|
||||
}
|
||||
}
|
||||
|
||||
// SerializeSCTList serializes a list of SCTs.
|
||||
func SerializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) {
|
||||
list := ctx509.SignedCertificateTimestampList{}
|
||||
for _, sct := range sctList {
|
||||
sctBytes, err := cttls.Marshal(sct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list.SCTList = append(list.SCTList, ctx509.SerializedSCT{Val: sctBytes})
|
||||
}
|
||||
return cttls.Marshal(list)
|
||||
}
|
||||
|
||||
// DeserializeSCTList deserializes a list of SCTs.
|
||||
func DeserializeSCTList(serializedSCTList []byte) ([]ct.SignedCertificateTimestamp, error) {
|
||||
var sctList ctx509.SignedCertificateTimestampList
|
||||
rest, err := cttls.Unmarshal(serializedSCTList, &sctList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT list contained trailing garbage"))
|
||||
}
|
||||
list := make([]ct.SignedCertificateTimestamp, len(sctList.SCTList))
|
||||
for i, serializedSCT := range sctList.SCTList {
|
||||
var sct ct.SignedCertificateTimestamp
|
||||
rest, err := cttls.Unmarshal(serializedSCT.Val, &sct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, errors.New("serialized SCT contained trailing garbage"))
|
||||
}
|
||||
list[i] = sct
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// SCTListFromOCSPResponse extracts the SCTList from an ocsp.Response,
|
||||
// returning an empty list if the SCT extension was not found or could not be
|
||||
// unmarshalled.
|
||||
func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTimestamp, error) {
|
||||
// This loop finds the SCTListExtension in the OCSP response.
|
||||
var SCTListExtension, ext pkix.Extension
|
||||
for _, ext = range response.Extensions {
|
||||
// sctExtOid is the ObjectIdentifier of a Signed Certificate Timestamp.
|
||||
sctExtOid := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5}
|
||||
if ext.Id.Equal(sctExtOid) {
|
||||
SCTListExtension = ext
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// This code block extracts the sctList from the SCT extension.
|
||||
var sctList []ct.SignedCertificateTimestamp
|
||||
var err error
|
||||
if numBytes := len(SCTListExtension.Value); numBytes != 0 {
|
||||
var serializedSCTList []byte
|
||||
rest := make([]byte, numBytes)
|
||||
copy(rest, SCTListExtension.Value)
|
||||
for len(rest) != 0 {
|
||||
rest, err = asn1.Unmarshal(rest, &serializedSCTList)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
|
||||
}
|
||||
}
|
||||
sctList, err = DeserializeSCTList(serializedSCTList)
|
||||
}
|
||||
return sctList, err
|
||||
}
|
||||
|
||||
// ReadBytes reads a []byte either from a file or an environment variable.
|
||||
// If valFile has a prefix of 'env:', the []byte is read from the environment
|
||||
// using the subsequent name. If the prefix is 'file:' the []byte is read from
|
||||
// the subsequent file. If no prefix is provided, valFile is assumed to be a
|
||||
// file path.
|
||||
func ReadBytes(valFile string) ([]byte, error) {
|
||||
switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) {
|
||||
case 1:
|
||||
return ioutil.ReadFile(valFile)
|
||||
case 2:
|
||||
switch splitVal[0] {
|
||||
case "env":
|
||||
return []byte(os.Getenv(splitVal[1])), nil
|
||||
case "file":
|
||||
return ioutil.ReadFile(splitVal[1])
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown prefix: %s", splitVal[0])
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("multiple prefixes: %s",
|
||||
strings.Join(splitVal[:len(splitVal)-1], ", "))
|
||||
}
|
||||
}
|
629
vendor/github.com/cloudflare/cfssl/helpers/helpers_test.go
generated
vendored
Normal file
629
vendor/github.com/cloudflare/cfssl/helpers/helpers_test.go
generated
vendored
Normal file
@ -0,0 +1,629 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ocsp"
|
||||
|
||||
"github.com/google/certificate-transparency-go"
|
||||
)
|
||||
|
||||
const (
|
||||
testCertFile = "testdata/cert.pem"
|
||||
testCertDERFile = "testdata/cert.der"
|
||||
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"
|
||||
testPrivateRSAKey = "testdata/priv_rsa_key.pem"
|
||||
testPrivateECDSAKey = "testdata/private_ecdsa_key.pem"
|
||||
testUnsupportedECDSAKey = "testdata/secp256k1-key.pem"
|
||||
testMessedUpPrivateKey = "testdata/messed_up_priv_key.pem"
|
||||
testEncryptedPrivateKey = "testdata/enc_priv_key.pem"
|
||||
testEmptyPem = "testdata/empty.pem"
|
||||
testNoHeaderCert = "testdata/noheadercert.pem"
|
||||
testSinglePKCS7 = "testdata/cert_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out cert_pkcs7.pem -in cert.pem
|
||||
testEmptyPKCS7DER = "testdata/empty_pkcs7.der" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.der -outform der
|
||||
testEmptyPKCS7PEM = "testdata/empty_pkcs7.pem" // openssl crl2pkcs7 -nocrl -out empty_pkcs7.pem -outform pem
|
||||
testMultiplePKCS7 = "testdata/bundle_pkcs7.pem"
|
||||
testPKCS12EmptyPswd = "testdata/emptypasswordpkcs12.p12"
|
||||
testPKCS12Passwordispassword = "testdata/passwordpkcs12.p12"
|
||||
testPKCS12MultipleCerts = "testdata/multiplecerts.p12"
|
||||
testCSRPEM = "testdata/test.csr.pem"
|
||||
testCSRPEMBad = "testdata/test.bad.csr.pem"
|
||||
)
|
||||
|
||||
func TestParseCertificatesDER(t *testing.T) {
|
||||
var password = []string{"password", "", ""}
|
||||
for i, testFile := range []string{testPKCS12Passwordispassword, testPKCS12EmptyPswd, testCertDERFile} {
|
||||
testDER, err := ioutil.ReadFile(testFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := ParseCertificatesDER(testDER, password[i]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Incorrect Password for PKCS12 formatted files
|
||||
if _, _, err := ParseCertificatesDER(testDER, "incorrectpassword"); err == nil && i != 2 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
testDER, err := ioutil.ReadFile(testEmptyPKCS7DER)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// PKCS7 with no certificates
|
||||
if _, _, err := ParseCertificatesDER(testDER, ""); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
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 != expected {
|
||||
t.Fatalf("Expected %v, got %v", expected, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonthsValid(t *testing.T) {
|
||||
var cert = &x509.Certificate{
|
||||
NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
|
||||
NotAfter: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
if MonthsValid(cert) != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
cert.NotAfter = time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC)
|
||||
if MonthsValid(cert) != 12 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// extra days should be rounded up to 1 month
|
||||
cert.NotAfter = time.Date(2016, time.April, 02, 0, 0, 0, 0, time.UTC)
|
||||
if MonthsValid(cert) != 13 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasValidExpiry(t *testing.T) {
|
||||
// Issue period > April 1, 2015
|
||||
var cert = &x509.Certificate{
|
||||
NotBefore: time.Date(2015, time.April, 01, 0, 0, 0, 0, time.UTC),
|
||||
NotAfter: time.Date(2016, time.April, 01, 0, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
if !ValidExpiry(cert) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
cert.NotAfter = time.Date(2019, time.April, 01, 01, 0, 0, 0, time.UTC)
|
||||
if ValidExpiry(cert) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// Issue period < July 1, 2012
|
||||
cert.NotBefore = time.Date(2009, time.March, 01, 0, 0, 0, 0, time.UTC)
|
||||
if ValidExpiry(cert) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// Issue period July 1, 2012 - April 1, 2015
|
||||
cert.NotBefore = time.Date(2012, time.July, 01, 0, 0, 0, 0, time.UTC)
|
||||
cert.NotAfter = time.Date(2017, time.July, 01, 0, 0, 0, 0, time.UTC)
|
||||
if !ValidExpiry(cert) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
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, testSinglePKCS7} {
|
||||
certPEM, err := ioutil.ReadFile(testFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ParseCertificatePEM(certPEM); err != nil {
|
||||
t.Log(testFile)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, testFile := range []string{testBundleFile, testMessedUpCertFile, testEmptyPKCS7PEM, testEmptyCertFile, testMultiplePKCS7} {
|
||||
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, testSinglePKCS7, testMultiplePKCS7} {
|
||||
bundlePEM, err := ioutil.ReadFile(testFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ParseCertificatesPEM(bundlePEM); err != nil {
|
||||
t.Log(testFile)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// test failure cases
|
||||
// few lines deleted, then headers removed
|
||||
for _, testFile := range []string{testMessedUpBundleFile, testEmptyPKCS7PEM, 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 cases
|
||||
testRSAPEM, _ := ioutil.ReadFile(testPrivateRSAKey)
|
||||
_, err := ParsePrivateKeyPEM(testRSAPEM)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testECDSAPEM, _ := ioutil.ReadFile(testPrivateECDSAKey)
|
||||
_, err = ParsePrivateKeyPEM(testECDSAPEM)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// error cases
|
||||
errCases := []string{
|
||||
testMessedUpPrivateKey, // a few lines deleted
|
||||
testEmptyPem, // empty file
|
||||
testEncryptedPrivateKey, // encrypted key
|
||||
testUnsupportedECDSAKey, // ECDSA curve not currently supported by Go standard library
|
||||
}
|
||||
|
||||
for _, fname := range errCases {
|
||||
testPEM, _ := ioutil.ReadFile(fname)
|
||||
_, err = ParsePrivateKeyPEM(testPEM)
|
||||
if err == nil {
|
||||
t.Fatal("Incorrect private key failed to produce an error")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Imported from signers/local/testdata/
|
||||
const ecdsaTestCSR = "testdata/ecdsa256.csr"
|
||||
|
||||
func TestParseCSRPEM(t *testing.T) {
|
||||
in, err := ioutil.ReadFile(ecdsaTestCSR)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
_, _, err = ParseCSR(in)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
in[12]++
|
||||
_, _, err = ParseCSR(in)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an invalid CSR.")
|
||||
}
|
||||
in[12]--
|
||||
}
|
||||
|
||||
func TestParseCSRPEMMore(t *testing.T) {
|
||||
csrPEM, err := ioutil.ReadFile(testCSRPEM)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ParseCSRPEM(csrPEM); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
csrPEM, err = ioutil.ReadFile(testCSRPEMBad)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ParseCSRPEM(csrPEM); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ParseCSRPEM([]byte("not even pem")); err == nil {
|
||||
t.Fatal("Expected an invalid CSR.")
|
||||
}
|
||||
}
|
||||
|
||||
// Imported from signers/local/testdata/
|
||||
const rsaOldTestCSR = "testdata/rsa-old.csr"
|
||||
|
||||
func TestParseOldCSR(t *testing.T) {
|
||||
in, err := ioutil.ReadFile(rsaOldTestCSR)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
_, _, err = ParseCSR(in)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Imported from signers/local/testdata/
|
||||
const clientCertFile = "testdata/ca.pem"
|
||||
const clientKeyFile = "testdata/ca_key.pem"
|
||||
|
||||
func TestClientCertParams(t *testing.T) {
|
||||
_, err := LoadClientCertificate(testCertFile, testPrivateRSAKey)
|
||||
if err == nil {
|
||||
t.Fatal("Unmatched cert/key should generate error")
|
||||
}
|
||||
|
||||
cert, err := LoadClientCertificate("", "")
|
||||
if err != nil || cert != nil {
|
||||
t.Fatal("Certificate atempted to loaded with missing key and cert")
|
||||
}
|
||||
cert, err = LoadClientCertificate(clientCertFile, "")
|
||||
if err != nil || cert != nil {
|
||||
t.Fatal("Certificate atempted to loaded with missing key")
|
||||
}
|
||||
cert, err = LoadClientCertificate("", clientKeyFile)
|
||||
if err != nil || cert != nil {
|
||||
t.Fatal("Certificate atempted to loaded with missing cert")
|
||||
}
|
||||
|
||||
cert, err = LoadClientCertificate(clientCertFile, clientKeyFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cert == nil {
|
||||
t.Fatal("cert not created")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadPEMCertPool(t *testing.T) {
|
||||
certPool, err := PEMToCertPool([]byte{})
|
||||
if certPool != nil || err != nil {
|
||||
t.Fatal("Empty file name should not generate error or a cert pool")
|
||||
}
|
||||
|
||||
in, err := ioutil.ReadFile(testEmptyPem)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
certPool, err = PEMToCertPool(in)
|
||||
if certPool != nil {
|
||||
t.Fatal("Empty file should not generate a cert pool")
|
||||
} else if err == nil {
|
||||
t.Fatal("Expected error for empty file")
|
||||
}
|
||||
|
||||
in, err = ioutil.ReadFile(testEmptyCertFile)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
certPool, err = PEMToCertPool(in)
|
||||
if certPool != nil {
|
||||
t.Fatal("Empty cert should not generate a cert pool")
|
||||
} else if err == nil {
|
||||
t.Fatal("Expected error for empty cert")
|
||||
}
|
||||
|
||||
in, err = ioutil.ReadFile(clientCertFile)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
certPool, err = PEMToCertPool(in)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
} else if certPool == nil {
|
||||
t.Fatal("cert pool not created")
|
||||
}
|
||||
}
|
||||
|
||||
// sctEquals returns true if all fields of both SCTs are equivalent.
|
||||
func sctEquals(sctA, sctB ct.SignedCertificateTimestamp) bool {
|
||||
if sctA.SCTVersion == sctB.SCTVersion &&
|
||||
sctA.LogID == sctB.LogID &&
|
||||
sctA.Timestamp == sctB.Timestamp &&
|
||||
bytes.Equal(sctA.Extensions, sctB.Extensions) &&
|
||||
sctA.Signature.Algorithm == sctB.Signature.Algorithm &&
|
||||
bytes.Equal(sctA.Signature.Signature, sctA.Signature.Signature) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NOTE: TestDeserializeSCTList tests both DeserializeSCTList and
|
||||
// SerializeSCTList.
|
||||
func TestDeserializeSCTList(t *testing.T) {
|
||||
// Here we make sure that empty SCT lists return an error
|
||||
emptyLists := [][]byte{nil, {}}
|
||||
for _, emptyList := range emptyLists {
|
||||
_, err := DeserializeSCTList(emptyList)
|
||||
if err == nil {
|
||||
t.Fatalf("DeserializeSCTList(%v) should raise an error\n", emptyList)
|
||||
}
|
||||
}
|
||||
|
||||
// Here we make sure that an SCT list with a zero SCT is deserialized
|
||||
// correctly
|
||||
var zeroSCT ct.SignedCertificateTimestamp
|
||||
serializedSCT, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
deserializedSCTList, err := DeserializeSCTList(serializedSCT)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !sctEquals(zeroSCT, (deserializedSCTList)[0]) {
|
||||
t.Fatal("SCTs don't match")
|
||||
}
|
||||
|
||||
// Here we verify that an error is raised when the SCT list length
|
||||
// field is greater than its actual length
|
||||
serializedSCT, err = SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serializedSCT[0] = 15
|
||||
_, err = DeserializeSCTList(serializedSCT)
|
||||
if err == nil {
|
||||
t.Fatalf("DeserializeSCTList should raise an error when " +
|
||||
"the SCT list length field and the list length don't match\n")
|
||||
}
|
||||
|
||||
// Here we verify that an error is raised when the SCT list length
|
||||
// field is less than its actual length
|
||||
serializedSCT[0] = 0
|
||||
serializedSCT[1] = 0
|
||||
_, err = DeserializeSCTList(serializedSCT)
|
||||
if err == nil {
|
||||
t.Fatalf("DeserializeSCTList should raise an error when " +
|
||||
"the SCT list length field and the list length don't match\n")
|
||||
}
|
||||
|
||||
// Here we verify that an error is raised when the SCT length field is
|
||||
// greater than its actual length
|
||||
serializedSCT[0] = 0
|
||||
serializedSCT[1] = 49
|
||||
serializedSCT[2] = 1
|
||||
_, err = DeserializeSCTList(serializedSCT)
|
||||
if err == nil {
|
||||
t.Fatalf("DeserializeSCTList should raise an error when " +
|
||||
"the SCT length field and the SCT length don't match\n")
|
||||
}
|
||||
|
||||
// Here we verify that an error is raised when the SCT length field is
|
||||
// less than its actual length
|
||||
serializedSCT[2] = 0
|
||||
serializedSCT[3] = 0
|
||||
_, err = DeserializeSCTList(serializedSCT)
|
||||
if err == nil {
|
||||
t.Fatalf("DeserializeSCTList should raise an error when " +
|
||||
"the SCT length field and the SCT length don't match\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCTListFromOCSPResponse(t *testing.T) {
|
||||
var response ocsp.Response
|
||||
lst, err := SCTListFromOCSPResponse(&response)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(lst) != 0 {
|
||||
t.Fatal("SCTListFromOCSPResponse should return an empty SCT list for an empty extension")
|
||||
}
|
||||
|
||||
var zeroSCT ct.SignedCertificateTimestamp
|
||||
serializedSCTList, err := SerializeSCTList([]ct.SignedCertificateTimestamp{zeroSCT})
|
||||
if err != nil {
|
||||
t.Fatal("failed to serialize SCT list")
|
||||
}
|
||||
serializedSCTList, err = asn1.Marshal(serializedSCTList)
|
||||
if err != nil {
|
||||
t.Fatal("failed to serialize SCT list")
|
||||
}
|
||||
// The value of Id below is the object identifier of the OCSP Stapling
|
||||
// SCT extension (see section 3.3. of RFC 6962).
|
||||
response.Extensions = []pkix.Extension{{
|
||||
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5},
|
||||
Critical: false,
|
||||
Value: serializedSCTList,
|
||||
}}
|
||||
lst, err = SCTListFromOCSPResponse(&response)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !sctEquals(zeroSCT, lst[0]) {
|
||||
t.Fatal("SCTs don't match")
|
||||
}
|
||||
}
|
53
vendor/github.com/cloudflare/cfssl/helpers/testdata/bundle.pem
generated
vendored
Normal file
53
vendor/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-----
|
52
vendor/github.com/cloudflare/cfssl/helpers/testdata/bundle_pkcs7.pem
generated
vendored
Normal file
52
vendor/github.com/cloudflare/cfssl/helpers/testdata/bundle_pkcs7.pem
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PKCS7-----
|
||||
MIIJOAYJKoZIhvcNAQcCoIIJKTCCCSUCAQExADALBgkqhkiG9w0BBwGgggkLMIIE
|
||||
czCCAl2gAwIBAgIIDARj8BWNsscwCwYJKoZIhvcNAQELMIGMMQswCQYDVQQGEwJV
|
||||
UzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBFbmdpbmVl
|
||||
cmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2FsaWZvcm5p
|
||||
YTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wHhcNMTQwMzAyMDAwMDAw
|
||||
WhcNMTkwNDAxMDAwMDAwWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkNsb3Vk
|
||||
RmxhcmUxHDAaBgNVBAsTE1N5c3RlbXMgRW5naW5lZXJpbmcxFjAUBgNVBAcTDVNh
|
||||
biBGcmFuY2lzY28xEzARBgNVBAgTCkNhbGlmb3JuaWExHTAbBgNVBAMTFGNsb3Vk
|
||||
ZmxhcmUtaW50ZXIuY29tMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEIVkjNJGwf3F0
|
||||
XWJH7yQSVtxuoBidi5JNsQ7FhxEQcZEl3b+/1iF60TBY2Yi6KwJuA6nIE73PIXGy
|
||||
fNhThw4D8CiZbackQ/ufgz2DyvxyWFDPzLr7TXeM/0wSp/imoxWeo4GIMIGFMA4G
|
||||
A1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBRB+Yoi
|
||||
UjIm34/wBwHdJGE4Wufs/DAfBgNVHSMEGDAWgBTXXUgpaSwO9HOrQBxGqOOSFHsH
|
||||
EDAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWludGVyLmNvbTALBgkqhkiG9w0BAQsD
|
||||
ggIBACRqAC5EJEe+8ihv1WzCUMEMb7KtS0BqoNbdXE32ia66PgJSQmHcmeJdFI1U
|
||||
jL0DlljTM2tc+8KxR/1/qnKiI+W/D4wFTWOY/JWFOd15q7lXuKGl+8PMkAHFA145
|
||||
JCr6oZoO9G9wUwVUrbmXAbyPCOfzsEQ2+mD9F1ZpoEjzVhtGf0R+vnYrRw8j4WCv
|
||||
5AIcYRAf7HZxbhMILF1bccNlqyUtdH+/MTHXpjkjJjA5KbsHBrAEfjAXkD7cWWOa
|
||||
y6m7mVWb3PPFmGorP6t29baEETK9ZTZSrfD9rnExjjUCftWJEn0M4Pp98DvTbr6+
|
||||
bg8jwtq73qdyOfNsC/Sod18UuHH7MTQA22yqAF5jIlcYtAHGlNnl+sDPZACs369/
|
||||
Z9rOL9vPFL+Z3F/uJtqZzvN1QiCkj8jWzR0u9fh3eQwZADM2RwgwS4Gs2YghPsyp
|
||||
Do33sFOwfX93KqKBsTHssn8SSDDaSnZ8bu1ATEdshbVieecuQx40UadPuJpwEPVq
|
||||
TR5AhviXQ9bKrTnU5T7EgkW9vNydkpLQQlMg3QE8hsndv4loGZbZGfNtqQHS/mg1
|
||||
t07S+7OEa4YaMW+wVOBOqTdW7OXlZFLfCcF5SYLM0SnlTMklRMxiqI4JqZXH0thn
|
||||
UGD0JjfLX4rTaZUzT3lrXXWzpS2jzutXQkjGv4nhGGprIDuTMIIEkDCCA/ugAwIB
|
||||
AgIIWnP9jF/2nogwCwYJKoZIhvcNAQELMH0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI
|
||||
DApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRMwEQYDVQQKDApD
|
||||
bG91ZEZsYXJlMRQwEgYDVQQLDAtERVZfVEVTVElORzEWMBQGA1UEAwwNQ0ZTU0xf
|
||||
VEVTVF9DQTAeFw0xNDAzMDEwMDAwMDBaFw0xNDA0MTUwMDAwMDBaMIGMMQswCQYD
|
||||
VQQGEwJVUzETMBEGA1UEChMKQ2xvdWRGbGFyZTEcMBoGA1UECxMTU3lzdGVtcyBF
|
||||
bmdpbmVlcmluZzEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzETMBEGA1UECBMKQ2Fs
|
||||
aWZvcm5pYTEdMBsGA1UEAxMUY2xvdWRmbGFyZS1pbnRlci5jb20wggIiMA0GCSqG
|
||||
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDlCnV+vj0sVPy8SqHLAlI+xwnPhWgzj2Ve
|
||||
vD6Nz1Zu1BeQ5m5y4CWCf+GmRGTP7+a/C510Fw6rpmInB0NgxxwQ2rC08fJtCnij
|
||||
lGH/VjEPIHY5lRaAomcM8Rgx6JOuv9BpZJKpr9pyUMV53JeWRbWuLH5nEMdyk9Np
|
||||
etS2gWxt4/D20QlhK/tHkROrcLmEUddwIGdwE8JzI88c77Fuu6pgMtHKvl4GGH0y
|
||||
vb4T7PvCdH8V2tCH7bt8roXd9MSyFVy7uORkfouip7EsVREUmlcY5EvpR141KXbZ
|
||||
qiOQiusJ+u76mEUQNk8wCR1/CW/ii9v1BKOVjXwCfEtIXjg0APJx1VNSSH6XoDpU
|
||||
ETL+eQ4J0FL9XNbsDuYar7+zD0N1/5vSo3HLNRQR9f0lbsyssWBEN+CxK19xyPum
|
||||
r21Z0bU0f1B5H52VSF0q3I1Ju9wRo994a7YipdGcmZ2lChmT7r3mzlBTYl3poU26
|
||||
q34v8wG9U7Jv4fsZJ+RGebDI+TR3QG6Yod06l9oEYZxWXBY7STOs8wuTu3huSnan
|
||||
/IpWnV017Vsc61D5G+QrqcxZdXckt3anZKCF75JpUnJ7vuowTmmHlb8KIMa9mOvc
|
||||
uGX4P6mz8gTi2arl/aL27kj9Q0Jgv/y1ebe2Bx2P9TF6+VNDDL3J/vSVlFeqLt2r
|
||||
eAIBKnytLwIDAQABo4GIMIGFMA4GA1UdDwEB/wQEAwIApDASBgNVHRMBAf8ECDAG
|
||||
AQH/AgEBMB0GA1UdDgQWBBTXXUgpaSwO9HOrQBxGqOOSFHsHEDAfBgNVHSMEGDAW
|
||||
gBS4Xu+uZ1C31vMH5Wq+VbNnOg2SPjAfBgNVHREEGDAWghRjbG91ZGZsYXJlLWlu
|
||||
dGVyLmNvbTALBgkqhkiG9w0BAQsDgYEAfPLKCAHnPzgMYLX/fWznVvOEFAAYZByP
|
||||
Fx4QdMBbDZUtxHyvJIBs6PdxrdSuDwSiMqE7qQIi+jzzwGl9fC7vf45B2zCX0OW5
|
||||
1QL2oWNBdKlGgB+b2pwyME82lX/Pr7V1GY10u+ep1xdZDnchDaMsXjQQTJu0iuG3
|
||||
qKEuCmUwOmehADEA
|
||||
-----END PKCS7-----
|
56
vendor/github.com/cloudflare/cfssl/helpers/testdata/bundle_with_whitespace.pem
generated
vendored
Normal file
56
vendor/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-----
|
||||
|
27
vendor/github.com/cloudflare/cfssl/helpers/testdata/ca.pem
generated
vendored
Normal file
27
vendor/github.com/cloudflare/cfssl/helpers/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
vendor/github.com/cloudflare/cfssl/helpers/testdata/ca_key.pem
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/helpers/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-----
|
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert.der
generated
vendored
Normal file
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert.der
generated
vendored
Normal file
Binary file not shown.
13
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert.pem
generated
vendored
Normal file
13
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert.pem
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
|
||||
EDAOBgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0
|
||||
WjBMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
|
||||
U2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqG
|
||||
SM49AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574y
|
||||
hEIZOpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAd
|
||||
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNV
|
||||
HQ4EFgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/r
|
||||
urbw/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABl
|
||||
ZI+JifgG+2KCy9ln2LxGJQ==
|
||||
-----END CERTIFICATE-----
|
14
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert_pkcs7.pem
generated
vendored
Normal file
14
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert_pkcs7.pem
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
-----BEGIN PKCS7-----
|
||||
MIICHQYJKoZIhvcNAQcCoIICDjCCAgoCAQExADALBgkqhkiG9w0BBwGgggHwMIIB
|
||||
7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMCVVMx
|
||||
EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xEDAO
|
||||
BgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0WjBM
|
||||
MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2Fu
|
||||
IEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqGSM49
|
||||
AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574yhEIZ
|
||||
OpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAdBgNV
|
||||
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
|
||||
FgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/rurbw
|
||||
/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABlZI+J
|
||||
ifgG+2KCy9ln2LxGJaEAMQA=
|
||||
-----END PKCS7-----
|
15
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert_with_whitespace.pem
generated
vendored
Normal file
15
vendor/github.com/cloudflare/cfssl/helpers/testdata/cert_with_whitespace.pem
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIB7DCCAZKgAwIBAgIIE/Qz49ebG7kwCgYIKoZIzj0EAwIwTDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
|
||||
EDAOBgNVBAoTB2FjbWUuY28wHhcNMTcwNTIzMTk1MTQ0WhcNMTcwODIzMDE1NjQ0
|
||||
WjBMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
|
||||
U2FuIEZyYW5jaXNjbzEQMA4GA1UEChMHYWNtZS5jbzBZMBMGByqGSM49AgEGCCqG
|
||||
SM49AwEHA0IABEW8F+k/avvdBm/KRsuDnTZ3p+VuVdsqDF+aD9nIYeOhx5sj574y
|
||||
hEIZOpgbEsi3BvqY63y2jYyPFodf25+CA9GjXjBcMA4GA1UdDwEB/wQEAwIFoDAd
|
||||
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNV
|
||||
HQ4EFgQUzDpu+HN89EC1M8aNl7f0Ln5JnnIwCgYIKoZIzj0EAwIDSAAwRQIgC4/r
|
||||
urbw/pzE3LDA6GpIts6TVyzgftLLEfU2BzQsjp0CIQDo+sn8t7XC6JN4KKRr2ABl
|
||||
ZI+JifgG+2KCy9ln2LxGJQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
11
vendor/github.com/cloudflare/cfssl/helpers/testdata/ecdsa256.csr
generated
vendored
Normal file
11
vendor/github.com/cloudflare/cfssl/helpers/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-----
|
1
vendor/github.com/cloudflare/cfssl/helpers/testdata/empty.pem
generated
vendored
Normal file
1
vendor/github.com/cloudflare/cfssl/helpers/testdata/empty.pem
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
|
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/empty_pkcs7.der
generated
vendored
Normal file
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/empty_pkcs7.der
generated
vendored
Normal file
Binary file not shown.
3
vendor/github.com/cloudflare/cfssl/helpers/testdata/empty_pkcs7.pem
generated
vendored
Normal file
3
vendor/github.com/cloudflare/cfssl/helpers/testdata/empty_pkcs7.pem
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
-----BEGIN PKCS7-----
|
||||
MCcGCSqGSIb3DQEHAqAaMBgCAQExADALBgkqhkiG9w0BBwGgAKEAMQA=
|
||||
-----END PKCS7-----
|
2
vendor/github.com/cloudflare/cfssl/helpers/testdata/emptycert.pem
generated
vendored
Normal file
2
vendor/github.com/cloudflare/cfssl/helpers/testdata/emptycert.pem
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
-----END CERTIFICATE-----LSKFSKLF
|
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/emptypasswordpkcs12.p12
generated
vendored
Normal file
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/emptypasswordpkcs12.p12
generated
vendored
Normal file
Binary file not shown.
30
vendor/github.com/cloudflare/cfssl/helpers/testdata/enc_priv_key.pem
generated
vendored
Normal file
30
vendor/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
vendor/github.com/cloudflare/cfssl/helpers/testdata/messed_up_bundle.pem
generated
vendored
Normal file
48
vendor/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
vendor/github.com/cloudflare/cfssl/helpers/testdata/messed_up_priv_key.pem
generated
vendored
Normal file
20
vendor/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
vendor/github.com/cloudflare/cfssl/helpers/testdata/messedupcert.pem
generated
vendored
Normal file
11
vendor/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-----
|
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/multiplecerts.p12
generated
vendored
Normal file
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/multiplecerts.p12
generated
vendored
Normal file
Binary file not shown.
9
vendor/github.com/cloudflare/cfssl/helpers/testdata/noheadercert.pem
generated
vendored
Normal file
9
vendor/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
|
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/passwordpkcs12.p12
generated
vendored
Normal file
BIN
vendor/github.com/cloudflare/cfssl/helpers/testdata/passwordpkcs12.p12
generated
vendored
Normal file
Binary file not shown.
28
vendor/github.com/cloudflare/cfssl/helpers/testdata/priv_rsa_key.pem
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/helpers/testdata/priv_rsa_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-----
|
||||
|
5
vendor/github.com/cloudflare/cfssl/helpers/testdata/private_ecdsa_key.pem
generated
vendored
Normal file
5
vendor/github.com/cloudflare/cfssl/helpers/testdata/private_ecdsa_key.pem
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MGgCAQEEHCGXsrNo2xfy8+zd4Pzj8rcQ5KqQO43au1t/7nugBwYFK4EEACGhPAM6
|
||||
AASJodCTtj5aYXnWxMiYhwjEgNQJJbNzJFEbsGJX9pCWZC673ammTWFHMjnMPkS/
|
||||
9eU5YeW40BHqfw==
|
||||
-----END EC PRIVATE KEY-----
|
19
vendor/github.com/cloudflare/cfssl/helpers/testdata/rsa-old.csr
generated
vendored
Normal file
19
vendor/github.com/cloudflare/cfssl/helpers/testdata/rsa-old.csr
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
-----BEGIN NEW 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 NEW CERTIFICATE REQUEST-----
|
5
vendor/github.com/cloudflare/cfssl/helpers/testdata/secp256k1-key.pem
generated
vendored
Normal file
5
vendor/github.com/cloudflare/cfssl/helpers/testdata/secp256k1-key.pem
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHQCAQEEIJLKycmoCAk4HqlJGdsuFyHsxfIheKsLH91tS/TNP5OOoAcGBSuBBAAK
|
||||
oUQDQgAEBkmL7cvC2cgchzfSuUZPGnzH0FqBtf3kGhSllQiIzGDn4envPXNqp+93
|
||||
V2NZ8VT+Aba4ln2Vbp9gYrKquut5Zg==
|
||||
-----END EC PRIVATE KEY-----
|
15
vendor/github.com/cloudflare/cfssl/helpers/testdata/test.bad.csr.pem
generated
vendored
Normal file
15
vendor/github.com/cloudflare/cfssl/helpers/testdata/test.bad.csr.pem
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICzDCCAbQCAQAwgYYxCzAJBgNVBAYTAkVOMQ0wCwYDVQQIDARub25lMQ0wCwYD
|
||||
VQQHDARub25lMRIwEAYDVQQKDAlXaWtpcGVkaWExDTALBgNVBAsMBG5vbmUxGDAW
|
||||
BgNVBAMMDyoud2lraXBlZGlhLm9yZzEcMBoGCSqGSIb3DQEJARYNbm9uZUBub25l
|
||||
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMP/U8RlcCD6E8AL
|
||||
PT8LLUR9ygyygPCaSmIEC8zXGJung3ykElXFRz/Jc/bu0hxCxi2YDz5IjxBBOpB/
|
||||
kieG83HsSmZZtR+drZIQ6vOsr/ucvpnB9z4XzKuabNGZ5ZiTSQ9L7Mx8FzvUTq5y
|
||||
57HhA7ECAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4IBAQBn8OCVOIx+n0AS6WbEmYDR
|
||||
SspR9xOCoOwYfamB+2Bpmt82R01zJ/kaqzUtZUjaGvQvAaz5lUwoMdaO0X7I5Xfl
|
||||
sllMFDaYoGD4Rru4s8gz2qG/QHWA8uPXzJVAj6X0olbIdLTEqTKsnBj4Zr1AJCNy
|
||||
/YcG4ouLJr140o26MhwBpoCRpPjAgdYMH60BYfnc4/DILxMVqR9xqK1s98d6Ob/+
|
||||
3wHFK+S7BRWrJQXcM8veAexXuk9lHQ+FgGfD0eSYGz0kyP26Qa2pLTwumjt+nBPl
|
||||
rfJxaLHwTQ/1988G0H35ED0f9Md5fzoKi5evU1wG5WRxdEUPyt3QUXxdQ69i0C+7
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
|
18
vendor/github.com/cloudflare/cfssl/helpers/testdata/test.csr.pem
generated
vendored
Normal file
18
vendor/github.com/cloudflare/cfssl/helpers/testdata/test.csr.pem
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICzDCCAbQCAQAwgYYxCzAJBgNVBAYTAkVOMQ0wCwYDVQQIDARub25lMQ0wCwYD
|
||||
VQQHDARub25lMRIwEAYDVQQKDAlXaWtpcGVkaWExDTALBgNVBAsMBG5vbmUxGDAW
|
||||
BgNVBAMMDyoud2lraXBlZGlhLm9yZzEcMBoGCSqGSIb3DQEJARYNbm9uZUBub25l
|
||||
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMP/U8RlcCD6E8AL
|
||||
PT8LLUR9ygyygPCaSmIEC8zXGJung3ykElXFRz/Jc/bu0hxCxi2YDz5IjxBBOpB/
|
||||
kieG83HsSmZZtR+drZIQ6vOsr/ucvpnB9z4XzKuabNGZ5ZiTSQ9L7Mx8FzvUTq5y
|
||||
/ArIuM+FBeuno/IV8zvwAe/VRa8i0QjFXT9vBBp35aeatdnJ2ds50yKCsHHcjvtr
|
||||
9/8zPVqqmhl2XFS3Qdqlsprzbgksom67OobJGjaV+fNHNQ0o/rzP//Pl3i7vvaEG
|
||||
7Ff8tQhEwR9nJUR1T6Z7ln7S6cOr23YozgWVkEJ/dSr6LAopb+cZ88FzW5NszU6i
|
||||
57HhA7ECAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4IBAQBn8OCVOIx+n0AS6WbEmYDR
|
||||
SspR9xOCoOwYfamB+2Bpmt82R01zJ/kaqzUtZUjaGvQvAaz5lUwoMdaO0X7I5Xfl
|
||||
sllMFDaYoGD4Rru4s8gz2qG/QHWA8uPXzJVAj6X0olbIdLTEqTKsnBj4Zr1AJCNy
|
||||
/YcG4ouLJr140o26MhwBpoCRpPjAgdYMH60BYfnc4/DILxMVqR9xqK1s98d6Ob/+
|
||||
3wHFK+S7BRWrJQXcM8veAexXuk9lHQ+FgGfD0eSYGz0kyP26Qa2pLTwumjt+nBPl
|
||||
rfJxaLHwTQ/1988G0H35ED0f9Md5fzoKi5evU1wG5WRxdEUPyt3QUXxdQ69i0C+7
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
|
15
vendor/github.com/cloudflare/cfssl/info/info.go
generated
vendored
Normal file
15
vendor/github.com/cloudflare/cfssl/info/info.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Package info contains the definitions for the info endpoint
|
||||
package info
|
||||
|
||||
// Req is the request struct for an info API request.
|
||||
type Req struct {
|
||||
Label string `json:"label"`
|
||||
Profile string `json:"profile"`
|
||||
}
|
||||
|
||||
// Resp is the response for an Info API request.
|
||||
type Resp struct {
|
||||
Certificate string `json:"certificate"`
|
||||
Usage []string `json:"usages"`
|
||||
ExpiryString string `json:"expiry"`
|
||||
}
|
249
vendor/github.com/cloudflare/cfssl/initca/initca.go
generated
vendored
Normal file
249
vendor/github.com/cloudflare/cfssl/initca/initca.go
generated
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
// Package initca contains code to initialise a certificate authority,
|
||||
// generating a new root key and certificate.
|
||||
package initca
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
"github.com/cloudflare/cfssl/signer/local"
|
||||
)
|
||||
|
||||
// validator contains the default validation logic for certificate
|
||||
// authority certificates. The only requirement here is that the
|
||||
// certificate have a non-empty subject field.
|
||||
func validator(req *csr.CertificateRequest) error {
|
||||
if req.CN != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(req.Names) == 0 {
|
||||
return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
|
||||
}
|
||||
|
||||
for i := range req.Names {
|
||||
if csr.IsNameEmpty(req.Names[i]) {
|
||||
return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// New creates a new root certificate from the certificate request.
|
||||
func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
|
||||
policy := CAPolicy()
|
||||
if req.CA != nil {
|
||||
if req.CA.Expiry != "" {
|
||||
policy.Default.ExpiryString = req.CA.Expiry
|
||||
policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if req.CA.Backdate != "" {
|
||||
policy.Default.Backdate, err = time.ParseDuration(req.CA.Backdate)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
|
||||
if req.CA.PathLength != 0 && req.CA.PathLenZero {
|
||||
log.Infof("ignore invalid 'pathlenzero' value")
|
||||
} else {
|
||||
policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
|
||||
}
|
||||
}
|
||||
|
||||
g := &csr.Generator{Validator: validator}
|
||||
csrPEM, key, err = g.ProcessRequest(req)
|
||||
if err != nil {
|
||||
log.Errorf("failed to process request: %v", err)
|
||||
key = nil
|
||||
return
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(key)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse private key: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
|
||||
if err != nil {
|
||||
log.Errorf("failed to create signer: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
|
||||
cert, err = s.Sign(signReq)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// NewFromPEM creates a new root certificate from the key file passed in.
|
||||
func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
|
||||
privData, err := helpers.ReadBytes(keyFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(privData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return NewFromSigner(req, priv)
|
||||
}
|
||||
|
||||
// RenewFromPEM re-creates a root certificate from the CA cert and key
|
||||
// files. The resulting root certificate will have the input CA certificate
|
||||
// as the template and have the same expiry length. E.g. the existing CA
|
||||
// is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
|
||||
// will be valid from now and expire in one year as well.
|
||||
func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
|
||||
caBytes, err := helpers.ReadBytes(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ca, err := helpers.ParseCertificatePEM(caBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyBytes, err := helpers.ReadBytes(keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return RenewFromSigner(ca, key)
|
||||
}
|
||||
|
||||
// NewFromSigner creates a new root certificate from a crypto.Signer.
|
||||
func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
|
||||
policy := CAPolicy()
|
||||
if req.CA != nil {
|
||||
if req.CA.Expiry != "" {
|
||||
policy.Default.ExpiryString = req.CA.Expiry
|
||||
policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
|
||||
if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
|
||||
log.Infof("ignore invalid 'pathlenzero' value")
|
||||
} else {
|
||||
policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
|
||||
}
|
||||
}
|
||||
|
||||
csrPEM, err = csr.Generate(priv, req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
|
||||
if err != nil {
|
||||
log.Errorf("failed to create signer: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
signReq := signer.SignRequest{Request: string(csrPEM)}
|
||||
cert, err = s.Sign(signReq)
|
||||
return
|
||||
}
|
||||
|
||||
// RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer.
|
||||
// The resulting root certificate will have ca certificate
|
||||
// as the template and have the same expiry length. E.g. the existing CA
|
||||
// is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
|
||||
// will be valid from now and expire in one year as well.
|
||||
func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) {
|
||||
if !ca.IsCA {
|
||||
return nil, errors.New("input certificate is not a CA cert")
|
||||
}
|
||||
|
||||
// matching certificate public key vs private key
|
||||
switch {
|
||||
case ca.PublicKeyAlgorithm == x509.RSA:
|
||||
var rsaPublicKey *rsa.PublicKey
|
||||
var ok bool
|
||||
if rsaPublicKey, ok = priv.Public().(*rsa.PublicKey); !ok {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
if ca.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
case ca.PublicKeyAlgorithm == x509.ECDSA:
|
||||
var ecdsaPublicKey *ecdsa.PublicKey
|
||||
var ok bool
|
||||
if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
default:
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.NotRSAOrECC)
|
||||
}
|
||||
|
||||
req := csr.ExtractCertificateRequest(ca)
|
||||
cert, _, err := NewFromSigner(req, priv)
|
||||
return cert, err
|
||||
|
||||
}
|
||||
|
||||
// CAPolicy contains the CA issuing policy as default policy.
|
||||
var CAPolicy = func() *config.Signing {
|
||||
return &config.Signing{
|
||||
Default: &config.SigningProfile{
|
||||
Usage: []string{"cert sign", "crl sign"},
|
||||
ExpiryString: "43800h",
|
||||
Expiry: 5 * helpers.OneYear,
|
||||
CAConstraint: config.CAConstraint{IsCA: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Update copies the CA certificate, updates the NotBefore and
|
||||
// NotAfter fields, and then re-signs the certificate.
|
||||
func Update(ca *x509.Certificate, priv crypto.Signer) (cert []byte, err error) {
|
||||
copy, err := x509.ParseCertificate(ca.Raw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
validity := ca.NotAfter.Sub(ca.NotBefore)
|
||||
copy.NotBefore = time.Now().Round(time.Minute).Add(-5 * time.Minute)
|
||||
copy.NotAfter = copy.NotBefore.Add(validity)
|
||||
cert, err = x509.CreateCertificate(rand.Reader, copy, copy, priv.Public(), priv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
|
||||
return
|
||||
}
|
385
vendor/github.com/cloudflare/cfssl/initca/initca_test.go
generated
vendored
Normal file
385
vendor/github.com/cloudflare/cfssl/initca/initca_test.go
generated
vendored
Normal file
@ -0,0 +1,385 @@
|
||||
package initca
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
"github.com/cloudflare/cfssl/signer/local"
|
||||
)
|
||||
|
||||
var validKeyParams = []csr.BasicKeyRequest{
|
||||
{A: "rsa", S: 2048},
|
||||
{A: "rsa", S: 3072},
|
||||
{A: "rsa", S: 4096},
|
||||
{A: "ecdsa", S: 256},
|
||||
{A: "ecdsa", S: 384},
|
||||
{A: "ecdsa", S: 521},
|
||||
}
|
||||
|
||||
var validCAConfigs = []csr.CAConfig{
|
||||
{PathLength: 0, PathLenZero: true},
|
||||
{PathLength: 0, PathLenZero: false},
|
||||
{PathLength: 2},
|
||||
{PathLength: 2, Expiry: "1h"},
|
||||
// invalid PathLenZero value will be ignored
|
||||
{PathLength: 2, PathLenZero: true},
|
||||
}
|
||||
|
||||
var invalidCAConfig = csr.CAConfig{
|
||||
PathLength: 2,
|
||||
// Expiry must be a duration string
|
||||
Expiry: "2116/12/31",
|
||||
}
|
||||
var csrFiles = []string{
|
||||
"testdata/rsa2048.csr",
|
||||
"testdata/rsa3072.csr",
|
||||
"testdata/rsa4096.csr",
|
||||
"testdata/ecdsa256.csr",
|
||||
"testdata/ecdsa384.csr",
|
||||
"testdata/ecdsa521.csr",
|
||||
}
|
||||
|
||||
var testRSACAFile = "testdata/5min-rsa.pem"
|
||||
var testRSACAKeyFile = "testdata/5min-rsa-key.pem"
|
||||
var testECDSACAFile = "testdata/5min-ecdsa.pem"
|
||||
var testECDSACAKeyFile = "testdata/5min-ecdsa-key.pem"
|
||||
|
||||
var invalidCryptoParams = []csr.BasicKeyRequest{
|
||||
// Weak Key
|
||||
{A: "rsa", S: 1024},
|
||||
// Bad param
|
||||
{A: "rsaCrypto", S: 2048},
|
||||
{A: "ecdsa", S: 2000},
|
||||
}
|
||||
|
||||
func TestInitCA(t *testing.T) {
|
||||
var req *csr.CertificateRequest
|
||||
hostname := "cloudflare.com"
|
||||
for _, param := range validKeyParams {
|
||||
for _, caconfig := range validCAConfigs {
|
||||
req = &csr.CertificateRequest{
|
||||
Names: []csr.Name{
|
||||
{
|
||||
C: "US",
|
||||
ST: "California",
|
||||
L: "San Francisco",
|
||||
O: "CloudFlare",
|
||||
OU: "Systems Engineering",
|
||||
},
|
||||
},
|
||||
CN: hostname,
|
||||
Hosts: []string{hostname, "www." + hostname},
|
||||
KeyRequest: ¶m,
|
||||
CA: &caconfig,
|
||||
}
|
||||
certBytes, _, keyBytes, err := New(req)
|
||||
if err != nil {
|
||||
t.Fatal("InitCA failed:", err)
|
||||
}
|
||||
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
|
||||
if err != nil {
|
||||
t.Fatal("InitCA private key parsing failed:", err)
|
||||
}
|
||||
cert, err := helpers.ParseCertificatePEM(certBytes)
|
||||
if err != nil {
|
||||
t.Fatal("InitCA cert parsing failed:", err)
|
||||
}
|
||||
|
||||
// Verify key parameters.
|
||||
switch req.KeyRequest.Algo() {
|
||||
case "rsa":
|
||||
if cert.PublicKey.(*rsa.PublicKey).N.BitLen() != param.Size() {
|
||||
t.Fatal("Cert key length mismatch.")
|
||||
}
|
||||
if key.(*rsa.PrivateKey).N.BitLen() != param.Size() {
|
||||
t.Fatal("Private key length mismatch.")
|
||||
}
|
||||
case "ecdsa":
|
||||
if cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().BitSize != param.Size() {
|
||||
t.Fatal("Cert key length mismatch.")
|
||||
}
|
||||
if key.(*ecdsa.PrivateKey).Curve.Params().BitSize != param.Size() {
|
||||
t.Fatal("Private key length mismatch.")
|
||||
}
|
||||
}
|
||||
|
||||
// Verify CA MaxPathLen
|
||||
if caconfig.PathLength == 0 && cert.MaxPathLenZero != caconfig.PathLenZero {
|
||||
t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect %v, got %v", caconfig.PathLenZero, cert.MaxPathLenZero)
|
||||
}
|
||||
|
||||
if caconfig.PathLength != 0 {
|
||||
if cert.MaxPathLen != caconfig.PathLength {
|
||||
t.Fatalf("fail to init a CA cert with specified CA pathlen: expect %d, got %d", caconfig.PathLength, cert.MaxPathLen)
|
||||
}
|
||||
if cert.MaxPathLenZero != false {
|
||||
t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect false, got %t", cert.MaxPathLenZero)
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the default CAPolicy with a test (short expiry) version.
|
||||
CAPolicy = func() *config.Signing {
|
||||
return &config.Signing{
|
||||
Default: &config.SigningProfile{
|
||||
Usage: []string{"cert sign", "crl sign"},
|
||||
ExpiryString: "300s",
|
||||
Expiry: 300 * time.Second,
|
||||
CAConstraint: config.CAConstraint{IsCA: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Start a signer
|
||||
s, err := local.NewSigner(key, cert, signer.DefaultSigAlgo(key), nil)
|
||||
if err != nil {
|
||||
t.Fatal("Signer Creation error:", err)
|
||||
}
|
||||
s.SetPolicy(CAPolicy())
|
||||
|
||||
// Sign RSA and ECDSA customer CSRs.
|
||||
for _, csrFile := range csrFiles {
|
||||
csrBytes, err := ioutil.ReadFile(csrFile)
|
||||
if err != nil {
|
||||
t.Fatal("CSR loading error:", err)
|
||||
}
|
||||
req := signer.SignRequest{
|
||||
Request: string(csrBytes),
|
||||
Hosts: signer.SplitHosts(hostname),
|
||||
Profile: "",
|
||||
Label: "",
|
||||
}
|
||||
|
||||
bytes, err := s.Sign(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
customerCert, _ := helpers.ParseCertificatePEM(bytes)
|
||||
if customerCert.SignatureAlgorithm != s.SigAlgo() {
|
||||
t.Fatal("Signature Algorithm mismatch")
|
||||
}
|
||||
err = customerCert.CheckSignatureFrom(cert)
|
||||
if err != nil {
|
||||
t.Fatal("Signing CSR failed.", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestInvalidCAConfig(t *testing.T) {
|
||||
hostname := "example.com"
|
||||
req := &csr.CertificateRequest{
|
||||
Names: []csr.Name{
|
||||
{
|
||||
C: "US",
|
||||
ST: "California",
|
||||
L: "San Francisco",
|
||||
O: "CloudFlare",
|
||||
OU: "Systems Engineering",
|
||||
},
|
||||
},
|
||||
CN: hostname,
|
||||
Hosts: []string{hostname, "www." + hostname},
|
||||
KeyRequest: &validKeyParams[0],
|
||||
CA: &invalidCAConfig,
|
||||
}
|
||||
|
||||
_, _, _, err := New(req)
|
||||
if err == nil {
|
||||
t.Fatal("InitCA with bad CAConfig should fail:", err)
|
||||
}
|
||||
}
|
||||
func TestInvalidCryptoParams(t *testing.T) {
|
||||
var req *csr.CertificateRequest
|
||||
hostname := "cloudflare.com"
|
||||
for _, invalidParam := range invalidCryptoParams {
|
||||
req = &csr.CertificateRequest{
|
||||
Names: []csr.Name{
|
||||
{
|
||||
C: "US",
|
||||
ST: "California",
|
||||
L: "San Francisco",
|
||||
O: "CloudFlare",
|
||||
OU: "Systems Engineering",
|
||||
},
|
||||
},
|
||||
CN: hostname,
|
||||
Hosts: []string{hostname, "www." + hostname},
|
||||
KeyRequest: &invalidParam,
|
||||
}
|
||||
_, _, _, err := New(req)
|
||||
if err == nil {
|
||||
t.Fatal("InitCA with bad params should fail:", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), `"code":2400`) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type validation struct {
|
||||
r *csr.CertificateRequest
|
||||
v bool
|
||||
}
|
||||
|
||||
var testValidations = []validation{
|
||||
{&csr.CertificateRequest{}, false},
|
||||
{&csr.CertificateRequest{
|
||||
CN: "test CA",
|
||||
}, true},
|
||||
{&csr.CertificateRequest{
|
||||
Names: []csr.Name{{}},
|
||||
}, false},
|
||||
{&csr.CertificateRequest{
|
||||
Names: []csr.Name{
|
||||
{O: "Example CA"},
|
||||
},
|
||||
}, true},
|
||||
}
|
||||
|
||||
func TestValidations(t *testing.T) {
|
||||
for i, tv := range testValidations {
|
||||
err := validator(tv.r)
|
||||
if tv.v && err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
|
||||
if !tv.v && err == nil {
|
||||
t.Fatalf("%d: expected error, but no error was reported", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewRSA(t *testing.T) {
|
||||
certPEM, err := RenewFromPEM(testRSACAFile, testRSACAKeyFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// must parse ok
|
||||
cert, err := helpers.ParseCertificatePEM(certPEM)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !cert.IsCA {
|
||||
t.Fatal("renewed CA certificate is not CA")
|
||||
}
|
||||
|
||||
// cert expiry must be 5 minutes
|
||||
expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds()
|
||||
if expiry >= 301 || expiry <= 299 {
|
||||
t.Fatal("expiry is not correct:", expiry)
|
||||
}
|
||||
|
||||
// check subject
|
||||
|
||||
if cert.Subject.CommonName != "" {
|
||||
t.Fatal("Bad CommonName")
|
||||
}
|
||||
|
||||
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" {
|
||||
t.Fatal("Bad Subject")
|
||||
}
|
||||
|
||||
if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." {
|
||||
t.Fatal("Bad Subject")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewECDSA(t *testing.T) {
|
||||
certPEM, err := RenewFromPEM(testECDSACAFile, testECDSACAKeyFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// must parse ok
|
||||
cert, err := helpers.ParseCertificatePEM(certPEM)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !cert.IsCA {
|
||||
t.Fatal("renewed CA certificate is not CA")
|
||||
}
|
||||
|
||||
// cert expiry must be 5 minutes
|
||||
expiry := cert.NotAfter.Sub(cert.NotBefore).Seconds()
|
||||
if expiry >= 301 || expiry <= 299 {
|
||||
t.Fatal("expiry is not correct:", expiry)
|
||||
}
|
||||
|
||||
// check subject
|
||||
|
||||
if cert.Subject.CommonName != "" {
|
||||
t.Fatal("Bad CommonName")
|
||||
}
|
||||
|
||||
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "US" {
|
||||
t.Fatal("Bad Subject")
|
||||
}
|
||||
|
||||
if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "CloudFlare, Inc." {
|
||||
t.Fatal("Bad Subject")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewMismatch(t *testing.T) {
|
||||
_, err := RenewFromPEM(testECDSACAFile, testRSACAKeyFile)
|
||||
if err == nil {
|
||||
t.Fatal("Fail to detect cert/key mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenew(t *testing.T) {
|
||||
in, err := ioutil.ReadFile(testECDSACAFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cert, err := helpers.ParseCertificatePEM(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
in, err = ioutil.ReadFile(testECDSACAKeyFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
renewed, err := Update(cert, priv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
newCert, err := helpers.ParseCertificatePEM(renewed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(newCert.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
|
||||
t.Fatal("Update returned a certificate with different subject public key info")
|
||||
}
|
||||
|
||||
if !bytes.Equal(newCert.RawSubject, cert.RawSubject) {
|
||||
t.Fatal("Update returned a certificate with different subject info")
|
||||
}
|
||||
|
||||
if !bytes.Equal(newCert.RawIssuer, cert.RawIssuer) {
|
||||
t.Fatal("Update returned a certificate with different issuer info")
|
||||
}
|
||||
}
|
5
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-ecdsa-key.pem
generated
vendored
Normal file
5
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-ecdsa-key.pem
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIA8OzPeVZT0cXTAPdcXYefLRIqyUXa0f0SgYMJ2J1AVcoAoGCCqGSM49
|
||||
AwEHoUQDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI
|
||||
7LzfGbMU+KqWTgOwGhrPvpusep3fjw+dAQ==
|
||||
-----END EC PRIVATE KEY-----
|
15
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-ecdsa.pem
generated
vendored
Normal file
15
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-ecdsa.pem
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICUDCCAfagAwIBAgIIec5PjdpJcNYwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMC
|
||||
VVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3QgQ2Vy
|
||||
dGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYD
|
||||
VQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIzMDEwMFoXDTE1MTAwODIzMDYwMFow
|
||||
ejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNV
|
||||
BAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJh
|
||||
bmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0D
|
||||
AQcDQgAEoCV+bVOLTJMy38j50sc3vE5k41GMRgriFJt0g0OVX8yaOZ93CZTI7Lzf
|
||||
GbMU+KqWTgOwGhrPvpusep3fjw+dAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud
|
||||
EwEB/wQIMAYBAf8CAQIwHQYDVR0OBBYEFDpLhSKBN3njfb6cXQCdRLzCZt0ZMB8G
|
||||
A1UdIwQYMBaAFDpLhSKBN3njfb6cXQCdRLzCZt0ZMAoGCCqGSM49BAMCA0gAMEUC
|
||||
IFU3BmzntGGeXZu2qWZx249nYn37S0AkCnQ3rUtI31bdAiEAsPICnZ+GB8yCN26N
|
||||
OL+N8dHvXiOvZ9/Vl488pyWOccY=
|
||||
-----END CERTIFICATE-----
|
27
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-rsa-key.pem
generated
vendored
Normal file
27
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-rsa-key.pem
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAtrYWs9ao2CpLWWLMyJJr3Bw7eJu3vSImzoqsBuhAREMaeuHm
|
||||
vAwqbByVpdxu1o+t0u6cMp/1M4YwDSxD4Ny3zEUUGse6yZpyph0+whdHSn1LOCxY
|
||||
KVwMtcYaEswenm0a+s/b9BYpbLv6lPoJ8+6bQNDuyyracDzlvGgk/HabemqDly4+
|
||||
W64tlrMUDHBuHHIm5EMF1sqVcinLCS8KsVDVfg4qKfzsZbTw0dDo5GZh1lPslkk9
|
||||
y8NzRltZjfJ3y5acv7SvIlETpy41VxScplR+Ot/6sXNJY3aEBT10smPXPABDeWjx
|
||||
FbnU5xacL/pC7pnKy734sL4lkvzKPDWZPsNMEwIDAQABAoIBAHIFHBHKib+sVS1I
|
||||
7MbWKR1JOQvBEV6kK1eFTmlZEpIG1kWNJ/J+HRMum2zQLRMUwsL5SNyG2fv3Z5Ew
|
||||
6IMw+joteahkr/oTuixT39A7uq+PlRtPAQ1+digRoj/MxebT65xNjtO56MwEWxIR
|
||||
H5jsdFJ0kDCVY4/bUPrMexhZ5Bj1xM3j8wpCPlVv2b9Ic/FUD9p6tOZDFhfSluiE
|
||||
87VsFHUImNvu4p/BAKUuKiz58cPNDHPAABsPrJR2SVU59roC4QtEmaxbmDkXUtB1
|
||||
+o+ypJQ0saqoffzHq7URebrJU9u+AV51UWaqHjg5OAe8eElOou6MHYX8R9cWZmJX
|
||||
UQKPyVECgYEAyLqstNHtA7R7+r4bW8Tr/kF7z+VvCfV9wB6TPT+ycuv3aU5+HYgR
|
||||
YRs2RBRtwI625hPk7AXEdbMt3SKoKjcMNMSD3qUK+fJFEyvOqRXiMJ2pLg04GlYZ
|
||||
cOInJd0T1q3O2cNLZwcWB1L0/KiV0dYHc4p+p5hisai3T9w7QthTUr8CgYEA6QVW
|
||||
jcsSBRFCokf/GKpTCVXIeqDSwrcEwoZh/RN6PlvgDwjw08G2IxKdAFs3/wxbKWHT
|
||||
xss+LQiMyBL8aRJvBUfotj5e5ZYESaSDqdeYv0Sydl1vfxcknHpTBRUdbyDtsOQn
|
||||
4X1ZEmfa9vFWS5P9fTFBC0BU2zzrhSlfQb6g360CgYBmnT+zBGo07aw/p7XWuRmn
|
||||
lhRUWEbmgXAyqa69rfVs2IJXfD/umuO/j6izLvpYaNzJS7xIiD5BqUK1/ISZaCC+
|
||||
TQPY6uhslFSJk2iHed9y2PZmy2010XQaCBLZQWZl5d6L5lGCrtWtEtSY4RoN9mtC
|
||||
vrc2uCkkB0sG8V/+MRaPgwKBgBiML2oQkn1mLBbcbssyZjz9hHkmqA1LKn0zmu8G
|
||||
NkKLezcaQgSMy5s2QsPe2C9OJexeGek/T/V+iRYqqdyHzJpJ0QIh3+1fuGPpqNUj
|
||||
mTvNCN/fR/ejgH/bgxNt/gPO/Ds+TdU7Vz7RIggRtH2RwYqGvctpo4bVDBqjGR3b
|
||||
7yahAoGAAgH97uN2FU1ffK0OAfMA1N58ikq/bg07KnJxO2CP5hrgsWK2ZVfeHUmU
|
||||
3k+xqQHCIuew55yO0tARTrFAh3Rj+zarA+PrtnzqW82wCIn8Fym3PFzbK2qrIMie
|
||||
yp0p4nBXsRmzinrPWKUYlFyRNY3Tcbstm5gUw2S4czSwwQeM/No=
|
||||
-----END RSA PRIVATE KEY-----
|
23
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-rsa.pem
generated
vendored
Normal file
23
vendor/github.com/cloudflare/cfssl/initca/testdata/5min-rsa.pem
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3DCCAsSgAwIBAgIIfbm2I1hwBa8wDQYJKoZIhvcNAQELBQAwejELMAkGA1UE
|
||||
BhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAhBgNVBAsTGlRlc3Qg
|
||||
Q2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMw
|
||||
EQYDVQQIEwpDYWxpZm9ybmlhMB4XDTE1MTAwODIwMjEwMFoXDTE1MTAwODIwMjYw
|
||||
MFowejELMAkGA1UEBhMCVVMxGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIzAh
|
||||
BgNVBAsTGlRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRYwFAYDVQQHEw1TYW4g
|
||||
RnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlhMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAtrYWs9ao2CpLWWLMyJJr3Bw7eJu3vSImzoqsBuhAREMa
|
||||
euHmvAwqbByVpdxu1o+t0u6cMp/1M4YwDSxD4Ny3zEUUGse6yZpyph0+whdHSn1L
|
||||
OCxYKVwMtcYaEswenm0a+s/b9BYpbLv6lPoJ8+6bQNDuyyracDzlvGgk/HabemqD
|
||||
ly4+W64tlrMUDHBuHHIm5EMF1sqVcinLCS8KsVDVfg4qKfzsZbTw0dDo5GZh1lPs
|
||||
lkk9y8NzRltZjfJ3y5acv7SvIlETpy41VxScplR+Ot/6sXNJY3aEBT10smPXPABD
|
||||
eWjxFbnU5xacL/pC7pnKy734sL4lkvzKPDWZPsNMEwIDAQABo2YwZDAOBgNVHQ8B
|
||||
Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQUCHoGEI1RZ8JN
|
||||
7UZ4zcTRll8nnnAwHwYDVR0jBBgwFoAUCHoGEI1RZ8JN7UZ4zcTRll8nnnAwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAHRcbd6cSXV6IuT4jLV8k6OUUlxzobbiRnXJrLjy9Anx
|
||||
tyIUWv2XSh/4IEJa+/MLNIb28gU9Sa2y4GV1qAgOM5qUM2iQJyLem0pTg0WTVKlj
|
||||
ytEK1kUwQCNkc/xpDrPo5CbN3aDuW/VPntOJL1GSQzS7jzK3NeQ9sah9YYhk4Wsk
|
||||
jzHVI1sX+qzcuUqCIPhqmGR0JE8ZI5YzbMTZ4/B+oWxZ7EyzB8O+v6HVD4eQFBSq
|
||||
tyGhGbh7mUvuMpVJ8FIX4BA7QL+RwqNNtAMZKcxPjhy5I23nVclbTCz/NC2Dgp8H
|
||||
13uQsEpUZ65clgiTo4LuPzPiIouZh5cBWP4gGqbyyS4=
|
||||
-----END CERTIFICATE-----
|
11
vendor/github.com/cloudflare/cfssl/initca/testdata/README.md
generated
vendored
Normal file
11
vendor/github.com/cloudflare/cfssl/initca/testdata/README.md
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
1. To generate 5min-rsa.pem and 5min-rsa-key.pem
|
||||
```
|
||||
$ GOPATH/bin/cfssl gencert -initca ca_csr_rsa.json | GOPATH/bin/cfssljson -bare 5min-rsa
|
||||
```
|
||||
2. To generate 5min-ecdsa.pem and 5min-ecdsa-key.pem
|
||||
```
|
||||
$ GOPATH/bin/cfssl gencert -initca ca_csr_ecdsa.json | GOPATH/bin/cfssljson -bare 5min-ecdsa
|
||||
```
|
||||
|
||||
The above commands will generate 5min-rsa.csr and 5min-ecdsa.csr as well, but those
|
||||
files can be ignored.
|
18
vendor/github.com/cloudflare/cfssl/initca/testdata/ca_csr_ecdsa.json
generated
vendored
Normal file
18
vendor/github.com/cloudflare/cfssl/initca/testdata/ca_csr_ecdsa.json
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"key": {
|
||||
"algo": "ecdsa",
|
||||
"size": 256
|
||||
},
|
||||
"names": [
|
||||
{
|
||||
"C": "US",
|
||||
"L": "San Francisco",
|
||||
"ST": "California",
|
||||
"O": "CloudFlare, Inc.",
|
||||
"OU": "Test Certificate Authority"
|
||||
}
|
||||
],
|
||||
"ca": {
|
||||
"expiry": "5m"
|
||||
}
|
||||
}
|
18
vendor/github.com/cloudflare/cfssl/initca/testdata/ca_csr_rsa.json
generated
vendored
Normal file
18
vendor/github.com/cloudflare/cfssl/initca/testdata/ca_csr_rsa.json
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"names": [
|
||||
{
|
||||
"C": "US",
|
||||
"L": "San Francisco",
|
||||
"ST": "California",
|
||||
"O": "CloudFlare, Inc.",
|
||||
"OU": "Test Certificate Authority"
|
||||
}
|
||||
],
|
||||
"ca": {
|
||||
"expiry": "5m"
|
||||
}
|
||||
}
|
11
vendor/github.com/cloudflare/cfssl/initca/testdata/ecdsa256.csr
generated
vendored
Normal file
11
vendor/github.com/cloudflare/cfssl/initca/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-----
|
12
vendor/github.com/cloudflare/cfssl/initca/testdata/ecdsa384.csr
generated
vendored
Normal file
12
vendor/github.com/cloudflare/cfssl/initca/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
vendor/github.com/cloudflare/cfssl/initca/testdata/ecdsa521.csr
generated
vendored
Normal file
13
vendor/github.com/cloudflare/cfssl/initca/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-----
|
19
vendor/github.com/cloudflare/cfssl/initca/testdata/rsa2048.csr
generated
vendored
Normal file
19
vendor/github.com/cloudflare/cfssl/initca/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
vendor/github.com/cloudflare/cfssl/initca/testdata/rsa3072.csr
generated
vendored
Normal file
24
vendor/github.com/cloudflare/cfssl/initca/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
vendor/github.com/cloudflare/cfssl/initca/testdata/rsa4096.csr
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cfssl/initca/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-----
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user