Преглед на файлове

Put PKCS#12 behind a flag, and check in the vendored dependency

Filippo Valsorda преди 6 години
родител
ревизия
060fcce2db

+ 24 - 16
cert.go

@@ -21,10 +21,11 @@ import (
 	"os/user"
 	"path/filepath"
 	"regexp"
-	"software.sslmate.com/src/go-pkcs12"
 	"strconv"
 	"strings"
 	"time"
+
+	"software.sslmate.com/src/go-pkcs12"
 )
 
 var userAndHostname string
@@ -82,21 +83,23 @@ func (m *mkcert) makeCert(hosts []string) {
 		filename += "+" + strconv.Itoa(len(hosts)-1)
 	}
 
-	privDER, err := x509.MarshalPKCS8PrivateKey(priv)
-	fatalIfErr(err, "failed to encode certificate key")
-	err = ioutil.WriteFile(filename+"-key.pem", pem.EncodeToMemory(
-		&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0600)
-	fatalIfErr(err, "failed to save certificate key")
-
-	err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory(
-		&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
-	fatalIfErr(err, "failed to save certificate key")
+	if !m.pkcs12 {
+		privDER, err := x509.MarshalPKCS8PrivateKey(priv)
+		fatalIfErr(err, "failed to encode certificate key")
+		err = ioutil.WriteFile(filename+"-key.pem", pem.EncodeToMemory(
+			&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0600)
+		fatalIfErr(err, "failed to save certificate key")
 
-	// generate PKCS#12
-	domainCert, _ := x509.ParseCertificate(cert)
-	pfxData, _ := pkcs12.Encode(rand.Reader, priv, domainCert, []*x509.Certificate{m.caCert}, "changeit")
-	err = ioutil.WriteFile(filename+".p12", pfxData, 0644)
-	fatalIfErr(err, "failed to save PKCS#12")
+		err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory(
+			&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
+		fatalIfErr(err, "failed to save certificate key")
+	} else {
+		domainCert, _ := x509.ParseCertificate(cert)
+		pfxData, err := pkcs12.Encode(rand.Reader, priv, domainCert, []*x509.Certificate{m.caCert}, "changeit")
+		fatalIfErr(err, "failed to generate PKCS#12")
+		err = ioutil.WriteFile(filename+".p12", pfxData, 0644)
+		fatalIfErr(err, "failed to save PKCS#12")
+	}
 
 	secondLvlWildcardRegexp := regexp.MustCompile(`(?i)^\*\.[0-9a-z_-]+$`)
 	log.Printf("\nCreated a new certificate valid for the following names 📜")
@@ -106,7 +109,12 @@ func (m *mkcert) makeCert(hosts []string) {
 			log.Printf("   Warning: many browsers don't support second-level wildcards like %q ⚠️", h)
 		}
 	}
-	log.Printf("\nThe certificate is at \"./%s.pem\", and the key at \"./%s-key.pem\", and the PKCS#12 at \"./%s.p12\" ✅\n\n", filename, filename, filename)
+
+	if !m.pkcs12 {
+		log.Printf("\nThe certificate is at \"./%s.pem\" and the key at \"./%s-key.pem\" ✅\n\n", filename, filename)
+	} else {
+		log.Printf("\nThe PKCS#12 bundle is at \"./%s.p12\" ✅\n\n", filename)
+	}
 }
 
 // loadCA will load or create the CA at CAROOT.

+ 6 - 1
main.go

@@ -34,6 +34,9 @@ const usage = `Usage of mkcert:
 	$ mkcert '*.example.com'
 	Generate "_wildcard.example.com.pem" and "_wildcard.example.com-key.pem".
 
+	$ mkcert -pkcs12 example.com
+	Generate "example.com.p12" instead of a PEM file.
+
 	$ mkcert -uninstall
 	Uninstall the local CA (but do not delete it).
 
@@ -45,6 +48,7 @@ func main() {
 	log.SetFlags(0)
 	var installFlag = flag.Bool("install", false, "install the local root CA in the system trust store")
 	var uninstallFlag = flag.Bool("uninstall", false, "uninstall the local root CA from the system trust store")
+	var pkcs12Flag = flag.Bool("pkcs12", false, "generate PKCS#12 instead of PEM")
 	var carootFlag = flag.Bool("CAROOT", false, "print the CAROOT path")
 	flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), usage) }
 	flag.Parse()
@@ -59,7 +63,7 @@ func main() {
 		log.Fatalln("ERROR: you can't set -install and -uninstall at the same time")
 	}
 	(&mkcert{
-		installMode: *installFlag, uninstallMode: *uninstallFlag,
+		installMode: *installFlag, uninstallMode: *uninstallFlag, pkcs12: *pkcs12Flag,
 	}).Run(flag.Args())
 }
 
@@ -68,6 +72,7 @@ const keyName = "rootCA-key.pem"
 
 type mkcert struct {
 	installMode, uninstallMode bool
+	pkcs12                     bool
 
 	CAROOT string
 	caCert *x509.Certificate

+ 10 - 0
vendor/software.sslmate.com/src/go-pkcs12/.gitattributes

@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text

+ 2 - 0
vendor/software.sslmate.com/src/go-pkcs12/.gitignore

@@ -0,0 +1,2 @@
+# Add no patterns to .hgignore except for files generated by the build.
+last-change

+ 28 - 0
vendor/software.sslmate.com/src/go-pkcs12/LICENSE

@@ -0,0 +1,28 @@
+Copyright (c) 2015, 2018 Opsmate, Inc.
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * 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.
+   * Neither the name of Google Inc. 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
+OWNER 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.

+ 50 - 0
vendor/software.sslmate.com/src/go-pkcs12/bmp-string.go

@@ -0,0 +1,50 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+	"errors"
+	"unicode/utf16"
+)
+
+// bmpString returns s encoded in UCS-2 with a zero terminator.
+func bmpString(s string) ([]byte, error) {
+	// References:
+	// https://tools.ietf.org/html/rfc7292#appendix-B.1
+	// https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
+	//  - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes
+	//	  EncodeRune returns 0xfffd if the rune does not need special encoding
+	//  - the above RFC provides the info that BMPStrings are NULL terminated.
+
+	ret := make([]byte, 0, 2*len(s)+2)
+
+	for _, r := range s {
+		if t, _ := utf16.EncodeRune(r); t != 0xfffd {
+			return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
+		}
+		ret = append(ret, byte(r/256), byte(r%256))
+	}
+
+	return append(ret, 0, 0), nil
+}
+
+func decodeBMPString(bmpString []byte) (string, error) {
+	if len(bmpString)%2 != 0 {
+		return "", errors.New("pkcs12: odd-length BMP string")
+	}
+
+	// strip terminator if present
+	if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
+		bmpString = bmpString[:l-2]
+	}
+
+	s := make([]uint16, 0, len(bmpString)/2)
+	for len(bmpString) > 0 {
+		s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
+		bmpString = bmpString[2:]
+	}
+
+	return string(utf16.Decode(s)), nil
+}

+ 172 - 0
vendor/software.sslmate.com/src/go-pkcs12/crypto.go

@@ -0,0 +1,172 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+	"bytes"
+	"crypto/cipher"
+	"crypto/des"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+	"errors"
+
+	"software.sslmate.com/src/go-pkcs12/internal/rc2"
+)
+
+var (
+	oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
+	oidPBEWithSHAAnd40BitRC2CBC      = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6})
+)
+
+// pbeCipher is an abstraction of a PKCS#12 cipher.
+type pbeCipher interface {
+	// create returns a cipher.Block given a key.
+	create(key []byte) (cipher.Block, error)
+	// deriveKey returns a key derived from the given password and salt.
+	deriveKey(salt, password []byte, iterations int) []byte
+	// deriveKey returns an IV derived from the given password and salt.
+	deriveIV(salt, password []byte, iterations int) []byte
+}
+
+type shaWithTripleDESCBC struct{}
+
+func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) {
+	return des.NewTripleDESCipher(key)
+}
+
+func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte {
+	return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
+}
+
+func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte {
+	return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
+}
+
+type shaWith40BitRC2CBC struct{}
+
+func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) {
+	return rc2.New(key, len(key)*8)
+}
+
+func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte {
+	return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
+}
+
+func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte {
+	return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
+}
+
+type pbeParams struct {
+	Salt       []byte
+	Iterations int
+}
+
+func pbeCipherFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.Block, []byte, error) {
+	var cipherType pbeCipher
+
+	switch {
+	case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC):
+		cipherType = shaWithTripleDESCBC{}
+	case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC):
+		cipherType = shaWith40BitRC2CBC{}
+	default:
+		return nil, nil, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported")
+	}
+
+	var params pbeParams
+	if err := unmarshal(algorithm.Parameters.FullBytes, &params); err != nil {
+		return nil, nil, err
+	}
+
+	key := cipherType.deriveKey(params.Salt, password, params.Iterations)
+	iv := cipherType.deriveIV(params.Salt, password, params.Iterations)
+
+	block, err := cipherType.create(key)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return block, iv, nil
+}
+
+func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) {
+	block, iv, err := pbeCipherFor(algorithm, password)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil
+}
+
+func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) {
+	cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password)
+	if err != nil {
+		return nil, err
+	}
+
+	encrypted := info.Data()
+	if len(encrypted) == 0 {
+		return nil, errors.New("pkcs12: empty encrypted data")
+	}
+	if len(encrypted)%blockSize != 0 {
+		return nil, errors.New("pkcs12: input is not a multiple of the block size")
+	}
+	decrypted = make([]byte, len(encrypted))
+	cbc.CryptBlocks(decrypted, encrypted)
+
+	psLen := int(decrypted[len(decrypted)-1])
+	if psLen == 0 || psLen > blockSize {
+		return nil, ErrDecryption
+	}
+
+	if len(decrypted) < psLen {
+		return nil, ErrDecryption
+	}
+	ps := decrypted[len(decrypted)-psLen:]
+	decrypted = decrypted[:len(decrypted)-psLen]
+	if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 {
+		return nil, ErrDecryption
+	}
+
+	return
+}
+
+// decryptable abstracts an object that contains ciphertext.
+type decryptable interface {
+	Algorithm() pkix.AlgorithmIdentifier
+	Data() []byte
+}
+
+func pbEncrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) {
+	block, iv, err := pbeCipherFor(algorithm, password)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	return cipher.NewCBCEncrypter(block, iv), block.BlockSize(), nil
+}
+
+func pbEncrypt(info encryptable, decrypted []byte, password []byte) error {
+	cbc, blockSize, err := pbEncrypterFor(info.Algorithm(), password)
+	if err != nil {
+		return err
+	}
+
+	psLen := blockSize - len(decrypted)%blockSize
+	encrypted := make([]byte, len(decrypted)+psLen)
+	copy(encrypted[:len(decrypted)], decrypted)
+	copy(encrypted[len(decrypted):], bytes.Repeat([]byte{byte(psLen)}, psLen))
+	cbc.CryptBlocks(encrypted, encrypted)
+
+	info.SetData(encrypted)
+
+	return nil
+}
+
+// encryptable abstracts a object that contains ciphertext.
+type encryptable interface {
+	Algorithm() pkix.AlgorithmIdentifier
+	SetData([]byte)
+}

+ 23 - 0
vendor/software.sslmate.com/src/go-pkcs12/errors.go

@@ -0,0 +1,23 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import "errors"
+
+var (
+	// ErrDecryption represents a failure to decrypt the input.
+	ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding")
+
+	// ErrIncorrectPassword is returned when an incorrect password is detected.
+	// Usually, P12/PFX data is signed to be able to verify the password.
+	ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect")
+)
+
+// NotImplementedError indicates that the input is not currently supported.
+type NotImplementedError string
+
+func (e NotImplementedError) Error() string {
+	return "pkcs12: " + string(e)
+}

+ 271 - 0
vendor/software.sslmate.com/src/go-pkcs12/internal/rc2/rc2.go

@@ -0,0 +1,271 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rc2 implements the RC2 cipher
+/*
+https://www.ietf.org/rfc/rfc2268.txt
+http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf
+
+This code is licensed under the MIT license.
+*/
+package rc2
+
+import (
+	"crypto/cipher"
+	"encoding/binary"
+)
+
+// The rc2 block size in bytes
+const BlockSize = 8
+
+type rc2Cipher struct {
+	k [64]uint16
+}
+
+// New returns a new rc2 cipher with the given key and effective key length t1
+func New(key []byte, t1 int) (cipher.Block, error) {
+	// TODO(dgryski): error checking for key length
+	return &rc2Cipher{
+		k: expandKey(key, t1),
+	}, nil
+}
+
+func (*rc2Cipher) BlockSize() int { return BlockSize }
+
+var piTable = [256]byte{
+	0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
+	0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
+	0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
+	0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
+	0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
+	0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
+	0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
+	0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
+	0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
+	0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
+	0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
+	0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
+	0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
+	0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
+	0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
+	0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad,
+}
+
+func expandKey(key []byte, t1 int) [64]uint16 {
+
+	l := make([]byte, 128)
+	copy(l, key)
+
+	var t = len(key)
+	var t8 = (t1 + 7) / 8
+	var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8))))
+
+	for i := len(key); i < 128; i++ {
+		l[i] = piTable[l[i-1]+l[uint8(i-t)]]
+	}
+
+	l[128-t8] = piTable[l[128-t8]&tm]
+
+	for i := 127 - t8; i >= 0; i-- {
+		l[i] = piTable[l[i+1]^l[i+t8]]
+	}
+
+	var k [64]uint16
+
+	for i := range k {
+		k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256
+	}
+
+	return k
+}
+
+func rotl16(x uint16, b uint) uint16 {
+	return (x >> (16 - b)) | (x << b)
+}
+
+func (c *rc2Cipher) Encrypt(dst, src []byte) {
+
+	r0 := binary.LittleEndian.Uint16(src[0:])
+	r1 := binary.LittleEndian.Uint16(src[2:])
+	r2 := binary.LittleEndian.Uint16(src[4:])
+	r3 := binary.LittleEndian.Uint16(src[6:])
+
+	var j int
+
+	for j <= 16 {
+		// mix r0
+		r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+		r0 = rotl16(r0, 1)
+		j++
+
+		// mix r1
+		r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+		r1 = rotl16(r1, 2)
+		j++
+
+		// mix r2
+		r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+		r2 = rotl16(r2, 3)
+		j++
+
+		// mix r3
+		r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+		r3 = rotl16(r3, 5)
+		j++
+
+	}
+
+	r0 = r0 + c.k[r3&63]
+	r1 = r1 + c.k[r0&63]
+	r2 = r2 + c.k[r1&63]
+	r3 = r3 + c.k[r2&63]
+
+	for j <= 40 {
+		// mix r0
+		r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+		r0 = rotl16(r0, 1)
+		j++
+
+		// mix r1
+		r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+		r1 = rotl16(r1, 2)
+		j++
+
+		// mix r2
+		r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+		r2 = rotl16(r2, 3)
+		j++
+
+		// mix r3
+		r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+		r3 = rotl16(r3, 5)
+		j++
+
+	}
+
+	r0 = r0 + c.k[r3&63]
+	r1 = r1 + c.k[r0&63]
+	r2 = r2 + c.k[r1&63]
+	r3 = r3 + c.k[r2&63]
+
+	for j <= 60 {
+		// mix r0
+		r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+		r0 = rotl16(r0, 1)
+		j++
+
+		// mix r1
+		r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+		r1 = rotl16(r1, 2)
+		j++
+
+		// mix r2
+		r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+		r2 = rotl16(r2, 3)
+		j++
+
+		// mix r3
+		r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+		r3 = rotl16(r3, 5)
+		j++
+	}
+
+	binary.LittleEndian.PutUint16(dst[0:], r0)
+	binary.LittleEndian.PutUint16(dst[2:], r1)
+	binary.LittleEndian.PutUint16(dst[4:], r2)
+	binary.LittleEndian.PutUint16(dst[6:], r3)
+}
+
+func (c *rc2Cipher) Decrypt(dst, src []byte) {
+
+	r0 := binary.LittleEndian.Uint16(src[0:])
+	r1 := binary.LittleEndian.Uint16(src[2:])
+	r2 := binary.LittleEndian.Uint16(src[4:])
+	r3 := binary.LittleEndian.Uint16(src[6:])
+
+	j := 63
+
+	for j >= 44 {
+		// unmix r3
+		r3 = rotl16(r3, 16-5)
+		r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+		j--
+
+		// unmix r2
+		r2 = rotl16(r2, 16-3)
+		r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+		j--
+
+		// unmix r1
+		r1 = rotl16(r1, 16-2)
+		r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+		j--
+
+		// unmix r0
+		r0 = rotl16(r0, 16-1)
+		r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+		j--
+	}
+
+	r3 = r3 - c.k[r2&63]
+	r2 = r2 - c.k[r1&63]
+	r1 = r1 - c.k[r0&63]
+	r0 = r0 - c.k[r3&63]
+
+	for j >= 20 {
+		// unmix r3
+		r3 = rotl16(r3, 16-5)
+		r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+		j--
+
+		// unmix r2
+		r2 = rotl16(r2, 16-3)
+		r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+		j--
+
+		// unmix r1
+		r1 = rotl16(r1, 16-2)
+		r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+		j--
+
+		// unmix r0
+		r0 = rotl16(r0, 16-1)
+		r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+		j--
+
+	}
+
+	r3 = r3 - c.k[r2&63]
+	r2 = r2 - c.k[r1&63]
+	r1 = r1 - c.k[r0&63]
+	r0 = r0 - c.k[r3&63]
+
+	for j >= 0 {
+		// unmix r3
+		r3 = rotl16(r3, 16-5)
+		r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+		j--
+
+		// unmix r2
+		r2 = rotl16(r2, 16-3)
+		r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+		j--
+
+		// unmix r1
+		r1 = rotl16(r1, 16-2)
+		r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+		j--
+
+		// unmix r0
+		r0 = rotl16(r0, 16-1)
+		r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+		j--
+
+	}
+
+	binary.LittleEndian.PutUint16(dst[0:], r0)
+	binary.LittleEndian.PutUint16(dst[2:], r1)
+	binary.LittleEndian.PutUint16(dst[4:], r2)
+	binary.LittleEndian.PutUint16(dst[6:], r3)
+}

+ 59 - 0
vendor/software.sslmate.com/src/go-pkcs12/mac.go

@@ -0,0 +1,59 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+	"crypto/hmac"
+	"crypto/sha1"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+)
+
+type macData struct {
+	Mac        digestInfo
+	MacSalt    []byte
+	Iterations int `asn1:"optional,default:1"`
+}
+
+// from PKCS#7:
+type digestInfo struct {
+	Algorithm pkix.AlgorithmIdentifier
+	Digest    []byte
+}
+
+var (
+	oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
+)
+
+func verifyMac(macData *macData, message, password []byte) error {
+	if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
+		return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
+	}
+
+	key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
+
+	mac := hmac.New(sha1.New, key)
+	mac.Write(message)
+	expectedMAC := mac.Sum(nil)
+
+	if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
+		return ErrIncorrectPassword
+	}
+	return nil
+}
+
+func computeMac(macData *macData, message, password []byte) error {
+	if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
+		return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
+	}
+
+	key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
+
+	mac := hmac.New(sha1.New, key)
+	mac.Write(message)
+	macData.Mac.Digest = mac.Sum(nil)
+
+	return nil
+}

+ 170 - 0
vendor/software.sslmate.com/src/go-pkcs12/pbkdf.go

@@ -0,0 +1,170 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+	"bytes"
+	"crypto/sha1"
+	"math/big"
+)
+
+var (
+	one = big.NewInt(1)
+)
+
+// sha1Sum returns the SHA-1 hash of in.
+func sha1Sum(in []byte) []byte {
+	sum := sha1.Sum(in)
+	return sum[:]
+}
+
+// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of
+// repeats of pattern.
+func fillWithRepeats(pattern []byte, v int) []byte {
+	if len(pattern) == 0 {
+		return nil
+	}
+	outputLen := v * ((len(pattern) + v - 1) / v)
+	return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen]
+}
+
+func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
+	// implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments
+
+	//    Let H be a hash function built around a compression function f:
+
+	//       Z_2^u x Z_2^v -> Z_2^u
+
+	//    (that is, H has a chaining variable and output of length u bits, and
+	//    the message input to the compression function of H is v bits).  The
+	//    values for u and v are as follows:
+
+	//            HASH FUNCTION     VALUE u        VALUE v
+	//              MD2, MD5          128            512
+	//                SHA-1           160            512
+	//               SHA-224          224            512
+	//               SHA-256          256            512
+	//               SHA-384          384            1024
+	//               SHA-512          512            1024
+	//             SHA-512/224        224            1024
+	//             SHA-512/256        256            1024
+
+	//    Furthermore, let r be the iteration count.
+
+	//    We assume here that u and v are both multiples of 8, as are the
+	//    lengths of the password and salt strings (which we denote by p and s,
+	//    respectively) and the number n of pseudorandom bits required.  In
+	//    addition, u and v are of course non-zero.
+
+	//    For information on security considerations for MD5 [19], see [25] and
+	//    [1], and on those for MD2, see [18].
+
+	//    The following procedure can be used to produce pseudorandom bits for
+	//    a particular "purpose" that is identified by a byte called "ID".
+	//    This standard specifies 3 different values for the ID byte:
+
+	//    1.  If ID=1, then the pseudorandom bits being produced are to be used
+	//        as key material for performing encryption or decryption.
+
+	//    2.  If ID=2, then the pseudorandom bits being produced are to be used
+	//        as an IV (Initial Value) for encryption or decryption.
+
+	//    3.  If ID=3, then the pseudorandom bits being produced are to be used
+	//        as an integrity key for MACing.
+
+	//    1.  Construct a string, D (the "diversifier"), by concatenating v/8
+	//        copies of ID.
+	var D []byte
+	for i := 0; i < v; i++ {
+		D = append(D, ID)
+	}
+
+	//    2.  Concatenate copies of the salt together to create a string S of
+	//        length v(ceiling(s/v)) bits (the final copy of the salt may be
+	//        truncated to create S).  Note that if the salt is the empty
+	//        string, then so is S.
+
+	S := fillWithRepeats(salt, v)
+
+	//    3.  Concatenate copies of the password together to create a string P
+	//        of length v(ceiling(p/v)) bits (the final copy of the password
+	//        may be truncated to create P).  Note that if the password is the
+	//        empty string, then so is P.
+
+	P := fillWithRepeats(password, v)
+
+	//    4.  Set I=S||P to be the concatenation of S and P.
+	I := append(S, P...)
+
+	//    5.  Set c=ceiling(n/u).
+	c := (size + u - 1) / u
+
+	//    6.  For i=1, 2, ..., c, do the following:
+	A := make([]byte, c*20)
+	var IjBuf []byte
+	for i := 0; i < c; i++ {
+		//        A.  Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
+		//            H(H(H(... H(D||I))))
+		Ai := hash(append(D, I...))
+		for j := 1; j < r; j++ {
+			Ai = hash(Ai)
+		}
+		copy(A[i*20:], Ai[:])
+
+		if i < c-1 { // skip on last iteration
+			// B.  Concatenate copies of Ai to create a string B of length v
+			//     bits (the final copy of Ai may be truncated to create B).
+			var B []byte
+			for len(B) < v {
+				B = append(B, Ai[:]...)
+			}
+			B = B[:v]
+
+			// C.  Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
+			//     blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
+			//     setting I_j=(I_j+B+1) mod 2^v for each j.
+			{
+				Bbi := new(big.Int).SetBytes(B)
+				Ij := new(big.Int)
+
+				for j := 0; j < len(I)/v; j++ {
+					Ij.SetBytes(I[j*v : (j+1)*v])
+					Ij.Add(Ij, Bbi)
+					Ij.Add(Ij, one)
+					Ijb := Ij.Bytes()
+					// We expect Ijb to be exactly v bytes,
+					// if it is longer or shorter we must
+					// adjust it accordingly.
+					if len(Ijb) > v {
+						Ijb = Ijb[len(Ijb)-v:]
+					}
+					if len(Ijb) < v {
+						if IjBuf == nil {
+							IjBuf = make([]byte, v)
+						}
+						bytesShort := v - len(Ijb)
+						for i := 0; i < bytesShort; i++ {
+							IjBuf[i] = 0
+						}
+						copy(IjBuf[bytesShort:], Ijb)
+						Ijb = IjBuf
+					}
+					copy(I[j*v:(j+1)*v], Ijb)
+				}
+			}
+		}
+	}
+	//    7.  Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
+	//        bit string, A.
+
+	//    8.  Use the first n bits of A as the output of this entire process.
+	return A[:size]
+
+	//    If the above process is being used to generate a DES key, the process
+	//    should be used to create 64 random bits, and the key's parity bits
+	//    should be set after the 64 bits have been produced.  Similar concerns
+	//    hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any
+	//    similar keys with parity bits "built into them".
+}

+ 501 - 0
vendor/software.sslmate.com/src/go-pkcs12/pkcs12.go

@@ -0,0 +1,501 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkcs12 implements some of PKCS#12.
+//
+// This implementation is distilled from https://tools.ietf.org/html/rfc7292
+// and referenced documents. It is intended for decoding P12/PFX-stored
+// certificates and keys for use with the crypto/tls package.
+package pkcs12
+
+import (
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/sha1"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+	"encoding/hex"
+	"encoding/pem"
+	"errors"
+	"io"
+)
+
+var (
+	oidDataContentType          = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
+	oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
+
+	oidFriendlyName     = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
+	oidLocalKeyID       = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
+	oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
+)
+
+type pfxPdu struct {
+	Version  int
+	AuthSafe contentInfo
+	MacData  macData `asn1:"optional"`
+}
+
+type contentInfo struct {
+	ContentType asn1.ObjectIdentifier
+	Content     asn1.RawValue `asn1:"tag:0,explicit,optional"`
+}
+
+type encryptedData struct {
+	Version              int
+	EncryptedContentInfo encryptedContentInfo
+}
+
+type encryptedContentInfo struct {
+	ContentType                asn1.ObjectIdentifier
+	ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
+	EncryptedContent           []byte `asn1:"tag:0,optional"`
+}
+
+func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
+	return i.ContentEncryptionAlgorithm
+}
+
+func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
+
+func (i *encryptedContentInfo) SetData(data []byte) { i.EncryptedContent = data }
+
+type safeBag struct {
+	Id         asn1.ObjectIdentifier
+	Value      asn1.RawValue     `asn1:"tag:0,explicit"`
+	Attributes []pkcs12Attribute `asn1:"set,optional"`
+}
+
+type pkcs12Attribute struct {
+	Id    asn1.ObjectIdentifier
+	Value asn1.RawValue `asn1:"set"`
+}
+
+type encryptedPrivateKeyInfo struct {
+	AlgorithmIdentifier pkix.AlgorithmIdentifier
+	EncryptedData       []byte
+}
+
+func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
+	return i.AlgorithmIdentifier
+}
+
+func (i encryptedPrivateKeyInfo) Data() []byte {
+	return i.EncryptedData
+}
+
+func (i *encryptedPrivateKeyInfo) SetData(data []byte) {
+	i.EncryptedData = data
+}
+
+// PEM block types
+const (
+	certificateType = "CERTIFICATE"
+	privateKeyType  = "PRIVATE KEY"
+)
+
+// unmarshal calls asn1.Unmarshal, but also returns an error if there is any
+// trailing data after unmarshaling.
+func unmarshal(in []byte, out interface{}) error {
+	trailing, err := asn1.Unmarshal(in, out)
+	if err != nil {
+		return err
+	}
+	if len(trailing) != 0 {
+		return errors.New("pkcs12: trailing data found")
+	}
+	return nil
+}
+
+// ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
+func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
+	encodedPassword, err := bmpString(password)
+	if err != nil {
+		return nil, ErrIncorrectPassword
+	}
+
+	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
+
+	if err != nil {
+		return nil, err
+	}
+
+	blocks := make([]*pem.Block, 0, len(bags))
+	for _, bag := range bags {
+		block, err := convertBag(&bag, encodedPassword)
+		if err != nil {
+			return nil, err
+		}
+		blocks = append(blocks, block)
+	}
+
+	return blocks, nil
+}
+
+func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
+	block := &pem.Block{
+		Headers: make(map[string]string),
+	}
+
+	for _, attribute := range bag.Attributes {
+		k, v, err := convertAttribute(&attribute)
+		if err != nil {
+			return nil, err
+		}
+		block.Headers[k] = v
+	}
+
+	switch {
+	case bag.Id.Equal(oidCertBag):
+		block.Type = certificateType
+		certsData, err := decodeCertBag(bag.Value.Bytes)
+		if err != nil {
+			return nil, err
+		}
+		block.Bytes = certsData
+	case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
+		block.Type = privateKeyType
+
+		key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
+		if err != nil {
+			return nil, err
+		}
+
+		switch key := key.(type) {
+		case *rsa.PrivateKey:
+			block.Bytes = x509.MarshalPKCS1PrivateKey(key)
+		case *ecdsa.PrivateKey:
+			block.Bytes, err = x509.MarshalECPrivateKey(key)
+			if err != nil {
+				return nil, err
+			}
+		default:
+			return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
+		}
+	default:
+		return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
+	}
+	return block, nil
+}
+
+func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
+	isString := false
+
+	switch {
+	case attribute.Id.Equal(oidFriendlyName):
+		key = "friendlyName"
+		isString = true
+	case attribute.Id.Equal(oidLocalKeyID):
+		key = "localKeyId"
+	case attribute.Id.Equal(oidMicrosoftCSPName):
+		// This key is chosen to match OpenSSL.
+		key = "Microsoft CSP Name"
+		isString = true
+	default:
+		return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
+	}
+
+	if isString {
+		if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
+			return "", "", err
+		}
+		if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
+			return "", "", err
+		}
+	} else {
+		var id []byte
+		if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
+			return "", "", err
+		}
+		value = hex.EncodeToString(id)
+	}
+
+	return key, value, nil
+}
+
+// Decode extracts a certificate and private key from pfxData. This function
+// assumes that there is only one certificate and only one private key in the
+// pfxData.
+func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
+	encodedPassword, err := bmpString(password)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if len(bags) != 2 {
+		err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
+		return
+	}
+
+	for _, bag := range bags {
+		switch {
+		case bag.Id.Equal(oidCertBag):
+			if certificate != nil {
+				err = errors.New("pkcs12: expected exactly one certificate bag")
+			}
+
+			certsData, err := decodeCertBag(bag.Value.Bytes)
+			if err != nil {
+				return nil, nil, err
+			}
+			certs, err := x509.ParseCertificates(certsData)
+			if err != nil {
+				return nil, nil, err
+			}
+			if len(certs) != 1 {
+				err = errors.New("pkcs12: expected exactly one certificate in the certBag")
+				return nil, nil, err
+			}
+			certificate = certs[0]
+
+		case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
+			if privateKey != nil {
+				err = errors.New("pkcs12: expected exactly one key bag")
+			}
+
+			if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
+				return nil, nil, err
+			}
+		}
+	}
+
+	if certificate == nil {
+		return nil, nil, errors.New("pkcs12: certificate missing")
+	}
+	if privateKey == nil {
+		return nil, nil, errors.New("pkcs12: private key missing")
+	}
+
+	return
+}
+
+func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
+	pfx := new(pfxPdu)
+	if err := unmarshal(p12Data, pfx); err != nil {
+		return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
+	}
+
+	if pfx.Version != 3 {
+		return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
+	}
+
+	if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
+		return nil, nil, NotImplementedError("only password-protected PFX is implemented")
+	}
+
+	// unmarshal the explicit bytes in the content for type 'data'
+	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
+		return nil, nil, err
+	}
+
+	if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
+		return nil, nil, errors.New("pkcs12: no MAC in data")
+	}
+
+	if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
+		if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
+			// some implementations use an empty byte array
+			// for the empty string password try one more
+			// time with empty-empty password
+			password = nil
+			err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
+		}
+		if err != nil {
+			return nil, nil, err
+		}
+	}
+
+	var authenticatedSafe []contentInfo
+	if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
+		return nil, nil, err
+	}
+
+	if len(authenticatedSafe) != 2 {
+		return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
+	}
+
+	for _, ci := range authenticatedSafe {
+		var data []byte
+
+		switch {
+		case ci.ContentType.Equal(oidDataContentType):
+			if err := unmarshal(ci.Content.Bytes, &data); err != nil {
+				return nil, nil, err
+			}
+		case ci.ContentType.Equal(oidEncryptedDataContentType):
+			var encryptedData encryptedData
+			if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
+				return nil, nil, err
+			}
+			if encryptedData.Version != 0 {
+				return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
+			}
+			if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
+				return nil, nil, err
+			}
+		default:
+			return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
+		}
+
+		var safeContents []safeBag
+		if err := unmarshal(data, &safeContents); err != nil {
+			return nil, nil, err
+		}
+		bags = append(bags, safeContents...)
+	}
+
+	return bags, password, nil
+}
+
+// Encode produces pfxData containing one private key, an end-entity certificate, and any number of CA certificates.
+// It emulates the behavior of OpenSSL's PKCS12_create: it creates two SafeContents: one that's encrypted with RC2
+// and contains the certificates, and another that is unencrypted and contains the private key shrouded with 3DES.
+// The private key bag and the end-entity certificate bag have the LocalKeyId attribute set to the SHA-1 fingerprint
+// of the end-entity certificate.
+func Encode(rand io.Reader, privateKey interface{}, certificate *x509.Certificate, caCerts []*x509.Certificate, password string) (pfxData []byte, err error) {
+	encodedPassword, err := bmpString(password)
+	if err != nil {
+		return nil, err
+	}
+
+	var pfx pfxPdu
+	pfx.Version = 3
+
+	var certFingerprint = sha1.Sum(certificate.Raw)
+	var localKeyIdAttr pkcs12Attribute
+	localKeyIdAttr.Id = oidLocalKeyID
+	localKeyIdAttr.Value.Class = 0
+	localKeyIdAttr.Value.Tag = 17
+	localKeyIdAttr.Value.IsCompound = true
+	if localKeyIdAttr.Value.Bytes, err = asn1.Marshal(certFingerprint[:]); err != nil {
+		return nil, err
+	}
+
+	var certBags []safeBag
+	var certBag *safeBag
+	if certBag, err = makeCertBag(certificate.Raw, []pkcs12Attribute{localKeyIdAttr}); err != nil {
+		return nil, err
+	}
+	certBags = append(certBags, *certBag)
+
+	for _, cert := range caCerts {
+		if certBag, err = makeCertBag(cert.Raw, []pkcs12Attribute{}); err != nil {
+			return nil, err
+		}
+		certBags = append(certBags, *certBag)
+	}
+
+	var keyBag safeBag
+	keyBag.Id = oidPKCS8ShroundedKeyBag
+	keyBag.Value.Class = 2
+	keyBag.Value.Tag = 0
+	keyBag.Value.IsCompound = true
+	if keyBag.Value.Bytes, err = encodePkcs8ShroudedKeyBag(rand, privateKey, encodedPassword); err != nil {
+		return nil, err
+	}
+	keyBag.Attributes = append(keyBag.Attributes, localKeyIdAttr)
+
+	// Construct an authenticated safe with two SafeContents.
+	// The first SafeContents is encrypted and contains the cert bags.
+	// The second SafeContents is unencrypted and contains the shrouded key bag.
+	var authenticatedSafe [2]contentInfo
+	if authenticatedSafe[0], err = makeSafeContents(rand, certBags, encodedPassword); err != nil {
+		return nil, err
+	}
+	if authenticatedSafe[1], err = makeSafeContents(rand, []safeBag{keyBag}, nil); err != nil {
+		return nil, err
+	}
+
+	var authenticatedSafeBytes []byte
+	if authenticatedSafeBytes, err = asn1.Marshal(authenticatedSafe[:]); err != nil {
+		return nil, err
+	}
+
+	// compute the MAC
+	pfx.MacData.Mac.Algorithm.Algorithm = oidSHA1
+	pfx.MacData.MacSalt = make([]byte, 8)
+	if _, err = rand.Read(pfx.MacData.MacSalt); err != nil {
+		return nil, err
+	}
+	pfx.MacData.Iterations = 1
+	if err = computeMac(&pfx.MacData, authenticatedSafeBytes, encodedPassword); err != nil {
+		return nil, err
+	}
+
+	pfx.AuthSafe.ContentType = oidDataContentType
+	pfx.AuthSafe.Content.Class = 2
+	pfx.AuthSafe.Content.Tag = 0
+	pfx.AuthSafe.Content.IsCompound = true
+	if pfx.AuthSafe.Content.Bytes, err = asn1.Marshal(authenticatedSafeBytes); err != nil {
+		return nil, err
+	}
+
+	if pfxData, err = asn1.Marshal(pfx); err != nil {
+		return nil, errors.New("pkcs12: error writing P12 data: " + err.Error())
+	}
+	return
+}
+
+func makeCertBag(certBytes []byte, attributes []pkcs12Attribute) (certBag *safeBag, err error) {
+	certBag = new(safeBag)
+	certBag.Id = oidCertBag
+	certBag.Value.Class = 2
+	certBag.Value.Tag = 0
+	certBag.Value.IsCompound = true
+	if certBag.Value.Bytes, err = encodeCertBag(certBytes); err != nil {
+		return nil, err
+	}
+	certBag.Attributes = attributes
+	return
+}
+
+func makeSafeContents(rand io.Reader, bags []safeBag, password []byte) (ci contentInfo, err error) {
+	var data []byte
+	if data, err = asn1.Marshal(bags); err != nil {
+		return
+	}
+
+	if password == nil {
+		ci.ContentType = oidDataContentType
+		ci.Content.Class = 2
+		ci.Content.Tag = 0
+		ci.Content.IsCompound = true
+		if ci.Content.Bytes, err = asn1.Marshal(data); err != nil {
+			return
+		}
+	} else {
+		randomSalt := make([]byte, 8)
+		if _, err = rand.Read(randomSalt); err != nil {
+			return
+		}
+
+		var algo pkix.AlgorithmIdentifier
+		algo.Algorithm = oidPBEWithSHAAnd40BitRC2CBC
+		if algo.Parameters.FullBytes, err = asn1.Marshal(pbeParams{Salt: randomSalt, Iterations: 2048}); err != nil {
+			return
+		}
+
+		var encryptedData encryptedData
+		encryptedData.Version = 0
+		encryptedData.EncryptedContentInfo.ContentType = oidDataContentType
+		encryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm = algo
+		if err = pbEncrypt(&encryptedData.EncryptedContentInfo, data, password); err != nil {
+			return
+		}
+
+		ci.ContentType = oidEncryptedDataContentType
+		ci.Content.Class = 2
+		ci.Content.Tag = 0
+		ci.Content.IsCompound = true
+		if ci.Content.Bytes, err = asn1.Marshal(encryptedData); err != nil {
+			return
+		}
+	}
+	return
+}

+ 77 - 0
vendor/software.sslmate.com/src/go-pkcs12/pkcs8.go

@@ -0,0 +1,77 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rsa"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+	"errors"
+)
+
+type pkcs8 struct { // Duplicated from x509 package
+	Version    int
+	Algo       pkix.AlgorithmIdentifier
+	PrivateKey []byte
+}
+
+var ( // Duplicated from x509 package
+	oidPublicKeyRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+	oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
+)
+
+var ( // Duplicated from x509 package
+	oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
+	oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
+	oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
+	oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
+)
+
+func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { // Duplicated from x509 package
+	switch curve {
+	case elliptic.P224():
+		return oidNamedCurveP224, true
+	case elliptic.P256():
+		return oidNamedCurveP256, true
+	case elliptic.P384():
+		return oidNamedCurveP384, true
+	case elliptic.P521():
+		return oidNamedCurveP521, true
+	}
+
+	return nil, false
+}
+
+func marshalPKCS8PrivateKey(key interface{}) (der []byte, err error) {
+	var privKey pkcs8
+	switch key := key.(type) {
+	case *rsa.PrivateKey:
+		privKey.Algo.Algorithm = oidPublicKeyRSA
+		// This is a NULL parameters value which is technically
+		// superfluous, but most other code includes it.
+		privKey.Algo.Parameters = asn1.RawValue{
+			Tag: 5,
+		}
+		privKey.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
+	case *ecdsa.PrivateKey:
+		privKey.Algo.Algorithm = oidPublicKeyECDSA
+		namedCurveOID, ok := oidFromNamedCurve(key.Curve)
+		if !ok {
+			return nil, errors.New("pkcs12: unknown elliptic curve")
+		}
+		if privKey.Algo.Parameters.FullBytes, err = asn1.Marshal(namedCurveOID); err != nil {
+			return nil, errors.New("pkcs12: failed to embed OID of named curve in PKCS#8: " + err.Error())
+		}
+		if privKey.PrivateKey, err = x509.MarshalECPrivateKey(key); err != nil {
+			return nil, errors.New("pkcs12: failed to embed EC private key in PKCS#8: " + err.Error())
+		}
+	default:
+		return nil, errors.New("pkcs12: only RSA and ECDSA private keys supported")
+	}
+	return asn1.Marshal(privKey)
+}

+ 98 - 0
vendor/software.sslmate.com/src/go-pkcs12/safebags.go

@@ -0,0 +1,98 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+	"crypto/x509"
+	"encoding/asn1"
+	"errors"
+	"io"
+)
+
+var (
+	// see https://tools.ietf.org/html/rfc7292#appendix-D
+	oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1})
+	oidPKCS8ShroundedKeyBag    = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2})
+	oidCertBag                 = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3})
+)
+
+type certBag struct {
+	Id   asn1.ObjectIdentifier
+	Data []byte `asn1:"tag:0,explicit"`
+}
+
+func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) {
+	pkinfo := new(encryptedPrivateKeyInfo)
+	if err = unmarshal(asn1Data, pkinfo); err != nil {
+		return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error())
+	}
+
+	pkData, err := pbDecrypt(pkinfo, password)
+	if err != nil {
+		return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error())
+	}
+
+	ret := new(asn1.RawValue)
+	if err = unmarshal(pkData, ret); err != nil {
+		return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error())
+	}
+
+	if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil {
+		return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error())
+	}
+
+	return privateKey, nil
+}
+
+func encodePkcs8ShroudedKeyBag(rand io.Reader, privateKey interface{}, password []byte) (asn1Data []byte, err error) {
+	var pkData []byte
+	if pkData, err = marshalPKCS8PrivateKey(privateKey); err != nil {
+		return nil, errors.New("pkcs12: error encoding PKCS#8 private key: " + err.Error())
+	}
+
+	randomSalt := make([]byte, 8)
+	if _, err = rand.Read(randomSalt); err != nil {
+		return nil, errors.New("pkcs12: error reading random salt: " + err.Error())
+	}
+	var paramBytes []byte
+	if paramBytes, err = asn1.Marshal(pbeParams{Salt: randomSalt, Iterations: 2048}); err != nil {
+		return nil, errors.New("pkcs12: error encoding params: " + err.Error())
+	}
+
+	var pkinfo encryptedPrivateKeyInfo
+	pkinfo.AlgorithmIdentifier.Algorithm = oidPBEWithSHAAnd3KeyTripleDESCBC
+	pkinfo.AlgorithmIdentifier.Parameters.FullBytes = paramBytes
+
+	if err = pbEncrypt(&pkinfo, pkData, password); err != nil {
+		return nil, errors.New("pkcs12: error encrypting PKCS#8 shrouded key bag: " + err.Error())
+	}
+
+	if asn1Data, err = asn1.Marshal(pkinfo); err != nil {
+		return nil, errors.New("pkcs12: error encoding PKCS#8 shrouded key bag: " + err.Error())
+	}
+
+	return asn1Data, nil
+}
+
+func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) {
+	bag := new(certBag)
+	if err := unmarshal(asn1Data, bag); err != nil {
+		return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error())
+	}
+	if !bag.Id.Equal(oidCertTypeX509Certificate) {
+		return nil, NotImplementedError("only X509 certificates are supported")
+	}
+	return bag.Data, nil
+}
+
+func encodeCertBag(x509Certificates []byte) (asn1Data []byte, err error) {
+	var bag certBag
+	bag.Id = oidCertTypeX509Certificate
+	bag.Data = x509Certificates
+	if asn1Data, err = asn1.Marshal(bag); err != nil {
+		return nil, errors.New("pkcs12: error encoding cert bag: " + err.Error())
+	}
+	return asn1Data, nil
+}