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