22 Commits

Author SHA1 Message Date
Filippo Valsorda
44af1b6556 Force go stable to workaround travis-ci/gimme#157 2018-08-13 00:33:52 -04:00
Filippo Valsorda
5d14daf07b Add .travis.yml for releases 2018-08-13 00:27:25 -04:00
Filippo Valsorda
060fcce2db Put PKCS#12 behind a flag, and check in the vendored dependency 2018-08-12 23:29:13 -04:00
linux_china
6be76ae477 Add PKCS#12 generation with default password changeit
Merges #34
Fixes #20
2018-08-12 23:29:02 -04:00
Filippo Valsorda
53f1769ab5 Document Windows support and supported root stores 2018-08-12 22:34:54 -04:00
Filippo Valsorda
e5f9c16f8c Offer a less confusing warning about Firefox on Windows 2018-08-12 21:47:50 -04:00
Filippo Valsorda
5fc72d92bc Replace !os.IsNotExist with == nil
!os.IsNotExist would also be true for other errors which don't mean the
file exists.
2018-08-12 21:42:42 -04:00
Chad Retz
561c99875b Add Windows support (#46)
Fixes #42
2018-08-12 18:33:56 -07:00
Filippo Valsorda
61180c71ad Add support for Firefox Developer Edition
This also fixes a bug where we wouldn't install to Chrome on Linux if
Firefox wasn't also present.

Closes #48
Updates #51
2018-08-12 21:14:07 -04:00
Filippo Valsorda
ba12bc5899 Avoid printing a success message on error
Updates #51
2018-08-12 20:32:34 -04:00
Filippo Valsorda
62149df1a0 Switch AUR to released one 2018-08-05 17:39:56 -04:00
Adam Shannon
ae768be874 Support installing into Java's root store (#38) 2018-07-30 04:22:27 +02:00
Filippo Valsorda
fd504a1868 Add note about iOS bug to README 2018-07-30 03:55:50 +02:00
Filippo Valsorda
676d4cdf6b Add a CommonName field to the CA to work-around iOS UI bug
Fixes #47
2018-07-30 03:38:23 +02:00
Filippo Valsorda
9e258bad93 Add a SubjectKeyId to the root CA
Not really useful for #47, but good to have and a RFC 5280 MUST.

See https://twitter.com/FiloSottile/status/1023564776834826240
2018-07-30 03:38:23 +02:00
Filippo Valsorda
c3bf865b0c Show custom usage on -help 2018-07-29 19:30:33 +02:00
Emilien Devos
fdd8fe8e17 Add AUR for installing mkcert on Arch Linux (#23) 2018-07-29 15:52:22 +02:00
Adam Shannon
1e7d221386 firefox: prefer cert9.db and skip cert8.db when found (#13)
Fixes #12 (again)
2018-07-12 13:47:05 -04:00
Filippo Valsorda
5651e29aea Create CONTRIBUTING.md 2018-07-09 16:27:05 -04:00
Filippo Valsorda
b0f7a80e95 Fix getCAROOT switch statement 2018-07-06 20:09:58 -04:00
Lucas Garron
dbad5f86ec Use $XDG_DATA_HOME on macOS if it is set (#40) 2018-07-06 20:02:49 -04:00
Filippo Valsorda
779fa98126 Update README.md 2018-07-04 13:08:32 -04:00
24 changed files with 1915 additions and 73 deletions

21
.travis.yml Normal file
View File

@@ -0,0 +1,21 @@
language: go
sudo: false
go: stable
install: "# skip"
script:
- go vet
- GOOS=linux GOARCH=amd64 go build -o "mkcert-$(git describe --tags)-linux-amd64"
- GOOS=darwin GOARCH=amd64 go build -o "mkcert-$(git describe --tags)-darwin-amd64"
- GOOS=windows GOARCH=amd64 go build -o "mkcert-$(git describe --tags)-windows-amd64.exe"
deploy:
provider: releases
skip_cleanup: true
file_glob: true
file: "mkcert-*"
api_key:
secure: "Vd1M3TelYxwpWDe7qawK23LvSttF6xuOjwz9BQOlevidONDx/Wf2JwM8ggSt/mlvYp/FH57PX2TOWqTnVD0Hkt7Ds7CPyLSRwpgQdB8qqYBIuGBmWRXSoHc46qauWiSEJiGOO1/aqfwdROQlu/JvQyNEzzZsLsmqDIqwIOdYcauq3tYjkL48VKensGg0d8JcLuCZ+niXMOYrJa/3EdQFAij1ZlwYZt76dS/XcZ2BKhGexPOrgUaMyl9GOsd7fft71hS0aN4xDHbut5psbe1MJaGan0DUWBiCXLNjFwgFPtEHes3ddq98VVCv7iSDvO2E2nQuwoAS+pQgpPHNpiOzoomdbr/d5OGW2s2xy8tozjoQTUfUQ0wkfTG4YzFKj66xZ4Ut8+/LdN5TZvPITqQqyXJ3a3u0KSivOkjH6M+BtTQjPNY2dlPWJcufWHKVjzhHN82mHbivQyFmJZQ99RtVSr/Nx+wkKZB4nImif+CtJ3hFBdIjGQoruvmrbcC+2U6JaNGmSxxlt1/2he5KCjxsjm6S01cCsNR8ivciAuHi1LAoOza0aWELOMPQz09mvgWX92R/Bj5swgpxZoQr3MmytlTncs9S77Fv6WeUh4Em/fIRAeN8ffzK9t87DbjHgfXvdRKcOWTQbhH9wNUf0VeA58NibFktIZbQwP5088G/o4A="
on:
repo: FiloSottile/mkcert
tags: true

28
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,28 @@
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
## Community Guidelines
This project follows [Google's Open Source Community
Guidelines](https://opensource.google.com/conduct/).

11
Gopkg.lock generated
View File

@@ -34,9 +34,18 @@
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0" version = "v0.3.0"
[[projects]]
branch = "master"
name = "software.sslmate.com/src/go-pkcs12"
packages = [
".",
"internal/rc2"
]
revision = "2291e8f0f237e77e89ce233be7653ecca8cf391a"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "eb8c5336b6da0643bb04cf921e8e61c2966555c879bc20533b060724d71667c6" inputs-digest = "af41b15413cbd854c23022d16f6da65af1235c9510e4193a17efef737de71c70"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -36,3 +36,7 @@
[[constraint]] [[constraint]]
branch = "master" branch = "master"
name = "golang.org/x/net" name = "golang.org/x/net"
[[constraint]]
name = "software.sslmate.com/src/go-pkcs12"
branch = "master"

View File

@@ -52,9 +52,28 @@ go get -u github.com/FiloSottile/mkcert
$(go env GOPATH)/bin/mkcert $(go env GOPATH)/bin/mkcert
``` ```
Windows will be supported next. (PRs welcome!) On Arch Linux you can use your [AUR helper](https://wiki.archlinux.org/index.php/AUR_helpers) to install mkcert from the [PKGBUILD](https://aur.archlinux.org/packages/mkcert/).
Warning: the `rootCA-key.pem` file that mkcert automatically generates gives complete power to intercept secure requests from your machine. Do not share it. ```
yaourt -S mkcert
```
On Windows build from source (requires Go 1.10+), or use [the pre-built binaries](https://github.com/FiloSottile/mkcert/releases).
> **Warning**: the `rootCA-key.pem` file that mkcert automatically generates gives complete power to intercept secure requests from your machine. Do not share it.
## Supported root stores
mkcert supports the following root stores:
* macOS system store
* Windows system store
* Linux variants that provide either
* `update-ca-trust` (Fedora, RHEL, CentOS) or
* `update-ca-certificates` (Ubuntu, Debian)
* Firefox (macOS and Linux only)
* Chrome and Chromium
* Java (when `JAVA_HOME` is set)
## Advanced topics ## Advanced topics
@@ -62,7 +81,7 @@ Warning: the `rootCA-key.pem` file that mkcert automatically generates gives com
For the certificates to be trusted on mobile devices, you will have to install the root CA. It's the `rootCA.pem` file in the folder printed by `mkcert -CAROOT`. For the certificates to be trusted on mobile devices, you will have to install the root CA. It's the `rootCA.pem` file in the folder printed by `mkcert -CAROOT`.
On iOS, you can either email the CA to yourself, or serve it from an HTTP server. After installing it, you must [enable full trust in it](https://support.apple.com/en-nz/HT204477). On iOS, you can either use AirDrop, email the CA to yourself, or serve it from an HTTP server. After installing it, you must [enable full trust in it](https://support.apple.com/en-nz/HT204477). **Note**: earlier versions of mkcert ran into [an iOS bug](https://forums.developer.apple.com/thread/89568), if you can't see the root in "Certificate Trust Settings" you might have to update mkcert and [regenerate the root](https://github.com/FiloSottile/mkcert/issues/47#issuecomment-408724149).
For Android, you will have to install the CA and then enable user roots in the development build of your app. See [this StackOverflow answer](https://stackoverflow.com/a/22040887/749014). For Android, you will have to install the CA and then enable user roots in the development build of your app. See [this StackOverflow answer](https://stackoverflow.com/a/22040887/749014).

37
cert.go
View File

@@ -7,8 +7,10 @@ package main
import ( import (
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/sha1"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/asn1"
"encoding/pem" "encoding/pem"
"io/ioutil" "io/ioutil"
"log" "log"
@@ -22,6 +24,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"time" "time"
"software.sslmate.com/src/go-pkcs12"
) )
var userAndHostname string var userAndHostname string
@@ -79,6 +83,7 @@ func (m *mkcert) makeCert(hosts []string) {
filename += "+" + strconv.Itoa(len(hosts)-1) filename += "+" + strconv.Itoa(len(hosts)-1)
} }
if !m.pkcs12 {
privDER, err := x509.MarshalPKCS8PrivateKey(priv) privDER, err := x509.MarshalPKCS8PrivateKey(priv)
fatalIfErr(err, "failed to encode certificate key") fatalIfErr(err, "failed to encode certificate key")
err = ioutil.WriteFile(filename+"-key.pem", pem.EncodeToMemory( err = ioutil.WriteFile(filename+"-key.pem", pem.EncodeToMemory(
@@ -88,6 +93,13 @@ func (m *mkcert) makeCert(hosts []string) {
err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory( err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory(
&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644) &pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
fatalIfErr(err, "failed to save certificate key") 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_-]+$`) secondLvlWildcardRegexp := regexp.MustCompile(`(?i)^\*\.[0-9a-z_-]+$`)
log.Printf("\nCreated a new certificate valid for the following names 📜") log.Printf("\nCreated a new certificate valid for the following names 📜")
@@ -97,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(" Warning: many browsers don't support second-level wildcards like %q ⚠️", h)
} }
} }
if !m.pkcs12 {
log.Printf("\nThe certificate is at \"./%s.pem\" and the key at \"./%s-key.pem\" ✅\n\n", filename, filename) 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. // loadCA will load or create the CA at CAROOT.
@@ -134,17 +151,36 @@ func (m *mkcert) loadCA() {
func (m *mkcert) newCA() { func (m *mkcert) newCA() {
priv, err := rsa.GenerateKey(rand.Reader, 3072) priv, err := rsa.GenerateKey(rand.Reader, 3072)
fatalIfErr(err, "failed to generate the CA key") fatalIfErr(err, "failed to generate the CA key")
pub := priv.PublicKey
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
fatalIfErr(err, "failed to generate serial number") fatalIfErr(err, "failed to generate serial number")
spkiASN1, err := x509.MarshalPKIXPublicKey(&pub)
fatalIfErr(err, "failed to encode public key")
var spki struct {
Algorithm pkix.AlgorithmIdentifier
SubjectPublicKey asn1.BitString
}
_, err = asn1.Unmarshal(spkiASN1, &spki)
fatalIfErr(err, "failed to decode public key")
skid := sha1.Sum(spki.SubjectPublicKey.Bytes)
tpl := &x509.Certificate{ tpl := &x509.Certificate{
SerialNumber: serialNumber, SerialNumber: serialNumber,
Subject: pkix.Name{ Subject: pkix.Name{
Organization: []string{"mkcert development CA"}, Organization: []string{"mkcert development CA"},
OrganizationalUnit: []string{userAndHostname}, OrganizationalUnit: []string{userAndHostname},
// The CommonName is required by iOS to show the certificate in the
// "Certificate Trust Settings" menu.
// https://github.com/FiloSottile/mkcert/issues/47
CommonName: "mkcert " + userAndHostname,
}, },
SubjectKeyId: skid[:],
NotAfter: time.Now().AddDate(10, 0, 0), NotAfter: time.Now().AddDate(10, 0, 0),
NotBefore: time.Now(), NotBefore: time.Now(),
@@ -156,7 +192,6 @@ func (m *mkcert) newCA() {
MaxPathLenZero: true, MaxPathLenZero: true,
} }
pub := priv.PublicKey
cert, err := x509.CreateCertificate(rand.Reader, tpl, tpl, &pub, priv) cert, err := x509.CreateCertificate(rand.Reader, tpl, tpl, &pub, priv)
fatalIfErr(err, "failed to generate CA certificate") fatalIfErr(err, "failed to generate CA certificate")

95
main.go
View File

@@ -20,11 +20,37 @@ import (
"golang.org/x/net/idna" "golang.org/x/net/idna"
) )
const usage = `Usage of mkcert:
$ mkcert -install
Install the local CA in the system trust store.
$ mkcert example.org
Generate "example.org.pem" and "example.org-key.pem".
$ mkcert example.com myapp.dev localhost 127.0.0.1 ::1
Generate "example.com+4.pem" and "example.com+4-key.pem".
$ 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).
Change the CA certificate and key storage location by setting $CAROOT,
print it with "mkcert -CAROOT".
`
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
var installFlag = flag.Bool("install", false, "install the local root CA in the system trust store") 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 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") var carootFlag = flag.Bool("CAROOT", false, "print the CAROOT path")
flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), usage) }
flag.Parse() flag.Parse()
if *carootFlag { if *carootFlag {
if *installFlag || *uninstallFlag { if *installFlag || *uninstallFlag {
@@ -37,7 +63,7 @@ func main() {
log.Fatalln("ERROR: you can't set -install and -uninstall at the same time") log.Fatalln("ERROR: you can't set -install and -uninstall at the same time")
} }
(&mkcert{ (&mkcert{
installMode: *installFlag, uninstallMode: *uninstallFlag, installMode: *installFlag, uninstallMode: *uninstallFlag, pkcs12: *pkcs12Flag,
}).Run(flag.Args()) }).Run(flag.Args())
} }
@@ -46,6 +72,7 @@ const keyName = "rootCA-key.pem"
type mkcert struct { type mkcert struct {
installMode, uninstallMode bool installMode, uninstallMode bool
pkcs12 bool
CAROOT string CAROOT string
caCert *x509.Certificate caCert *x509.Certificate
@@ -79,37 +106,21 @@ func (m *mkcert) Run(args []string) {
warning = true warning = true
log.Println("Warning: the local CA is not installed in the system trust store! ⚠️") log.Println("Warning: the local CA is not installed in the system trust store! ⚠️")
} }
if hasNSS && !m.checkNSS() { if hasNSS && CertutilInstallHelp != "" && !m.checkNSS() {
warning = true warning = true
log.Printf("Warning: the local CA is not installed in the %s trust store! ⚠️", NSSBrowsers) log.Printf("Warning: the local CA is not installed in the %s trust store! ⚠️", NSSBrowsers)
} }
if hasJava && !m.checkJava() {
warning = true
log.Println("Warning: the local CA is not installed in the Java trust store! ⚠️")
}
if warning { if warning {
log.Println("Run \"mkcert -install\" to avoid verification errors ‼️") log.Println("Run \"mkcert -install\" to avoid verification errors ‼️")
} }
} }
if len(args) == 0 { if len(args) == 0 {
log.Printf(` log.Printf("\n%s", usage)
Usage:
$ mkcert -install
Install the local CA in the system trust store.
$ mkcert example.org
Generate "example.org.pem" and "example.org-key.pem".
$ mkcert example.com myapp.dev localhost 127.0.0.1 ::1
Generate "example.com+4.pem" and "example.com+4-key.pem".
$ mkcert '*.example.com'
Generate "_wildcard.example.com.pem" and "_wildcard.example.com-key.pem".
$ mkcert -uninstall
Uninstall the local CA (but do not delete it).
Change the CA certificate and key storage location by setting $CAROOT,
print it with "mkcert -CAROOT".
`)
return return
} }
@@ -137,25 +148,24 @@ func getCAROOT() string {
} }
var dir string var dir string
switch runtime.GOOS { switch {
case "windows": case runtime.GOOS == "windows":
dir = os.Getenv("LocalAppData") dir = os.Getenv("LocalAppData")
case "darwin": case os.Getenv("XDG_DATA_HOME") != "":
dir = os.Getenv("XDG_DATA_HOME")
case runtime.GOOS == "darwin":
dir = os.Getenv("HOME") dir = os.Getenv("HOME")
if dir == "" { if dir == "" {
return "" return ""
} }
dir = filepath.Join(dir, "Library", "Application Support") dir = filepath.Join(dir, "Library", "Application Support")
default: // Unix default: // Unix
dir = os.Getenv("XDG_DATA_HOME")
if dir == "" {
dir = os.Getenv("HOME") dir = os.Getenv("HOME")
if dir == "" { if dir == "" {
return "" return ""
} }
dir = filepath.Join(dir, ".local", "share") dir = filepath.Join(dir, ".local", "share")
} }
}
return filepath.Join(dir, "mkcert") return filepath.Join(dir, "mkcert")
} }
@@ -169,15 +179,25 @@ func (m *mkcert) install() {
printed = true printed = true
} }
if hasNSS && !m.checkNSS() { if hasNSS && !m.checkNSS() {
if hasCertutil { if hasCertutil && m.installNSS() {
m.installNSS()
log.Printf("The local CA is now installed in the %s trust store (requires browser restart)! 🦊", NSSBrowsers) log.Printf("The local CA is now installed in the %s trust store (requires browser restart)! 🦊", NSSBrowsers)
} else { } else if CertutilInstallHelp == "" {
log.Printf(`Note: %s support is not available on your platform. `, NSSBrowsers)
} else if !hasCertutil {
log.Printf(`Warning: "certutil" is not available, so the CA can't be automatically installed in %s! ⚠️`, NSSBrowsers) log.Printf(`Warning: "certutil" is not available, so the CA can't be automatically installed in %s! ⚠️`, NSSBrowsers)
log.Printf(`Install "certutil" with "%s" and re-run "mkcert -install" 👈`, CertutilInstallHelp) log.Printf(`Install "certutil" with "%s" and re-run "mkcert -install" 👈`, CertutilInstallHelp)
} }
printed = true printed = true
} }
if hasJava && !m.checkJava() {
if hasKeytool {
m.installJava()
log.Println("The local CA is now installed in Java's trust store! ☕️")
} else {
log.Println(`Warning: "keytool" is not available, so the CA can't be automatically installed in Java's trust store! ⚠️`)
}
printed = true
}
if printed { if printed {
log.Print("") log.Print("")
} }
@@ -187,13 +207,22 @@ func (m *mkcert) uninstall() {
if hasNSS { if hasNSS {
if hasCertutil { if hasCertutil {
m.uninstallNSS() m.uninstallNSS()
} else { } else if CertutilInstallHelp != "" {
log.Print("") log.Print("")
log.Printf(`Warning: "certutil" is not available, so the CA can't be automatically uninstalled from %s (if it was ever installed)! ⚠️`, NSSBrowsers) log.Printf(`Warning: "certutil" is not available, so the CA can't be automatically uninstalled from %s (if it was ever installed)! ⚠️`, NSSBrowsers)
log.Printf(`You can install "certutil" with "%s" and re-run "mkcert -uninstall" 👈`, CertutilInstallHelp) log.Printf(`You can install "certutil" with "%s" and re-run "mkcert -uninstall" 👈`, CertutilInstallHelp)
log.Print("") log.Print("")
} }
} }
if hasJava {
if hasKeytool {
m.uninstallJava()
} else {
log.Print("")
log.Println(`Warning: "keytool" is not available, so the CA can't be automatically uninstalled from Java's trust store (if it was ever installed)! ⚠️`)
log.Print("")
}
}
if m.uninstallPlatform() { if m.uninstallPlatform() {
log.Print("The local CA is now uninstalled from the system trust store(s)! 👋") log.Print("The local CA is now uninstalled from the system trust store(s)! 👋")
log.Print("") log.Print("")

View File

@@ -17,7 +17,6 @@ import (
) )
var ( var (
FirefoxPath = "/Applications/Firefox.app"
FirefoxProfile = os.Getenv("HOME") + "/Library/Application Support/Firefox/Profiles/*" FirefoxProfile = os.Getenv("HOME") + "/Library/Application Support/Firefox/Profiles/*"
CertutilInstallHelp = "brew install nss" CertutilInstallHelp = "brew install nss"
NSSBrowsers = "Firefox" NSSBrowsers = "Firefox"

107
truststore_java.go Normal file
View File

@@ -0,0 +1,107 @@
// Copyright 2018 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 main
import (
"bytes"
"crypto/sha1"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"hash"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
)
var (
hasJava bool
hasKeytool bool
javaHome string
cacertsPath string
keytoolPath string
storePass string = "changeit"
)
func init() {
if v := os.Getenv("JAVA_HOME"); v != "" {
hasJava = true
javaHome = v
_, err := os.Stat(path.Join(v, "bin/keytool"))
if err == nil {
hasKeytool = true
keytoolPath = path.Join(v, "bin/keytool")
}
cacertsPath = path.Join(v, "jre/lib/security/cacerts")
}
}
func (m *mkcert) checkJava() bool {
// exists returns true if the given x509.Certificate's fingerprint
// is in the keytool -list output
exists := func(c *x509.Certificate, h hash.Hash, keytoolOutput []byte) bool {
h.Write(c.Raw)
fp := strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return bytes.Contains(keytoolOutput, []byte(fp))
}
keytoolOutput, err := exec.Command(keytoolPath, "-list", "-keystore", cacertsPath, "-storepass", storePass).CombinedOutput()
fatalIfCmdErr(err, "keytool -list", keytoolOutput)
// keytool outputs SHA1 and SHA256 (Java 9+) certificates in uppercase hex
// with each octet pair delimitated by ":". Drop them from the keytool output
keytoolOutput = bytes.Replace(keytoolOutput, []byte(":"), nil, -1)
// pre-Java 9 uses SHA1 fingerprints
s1, s256 := sha1.New(), sha256.New()
return exists(m.caCert, s1, keytoolOutput) || exists(m.caCert, s256, keytoolOutput)
}
func (m *mkcert) installJava() {
args := []string{
"-importcert", "-noprompt",
"-keystore", cacertsPath,
"-storepass", storePass,
"-file", filepath.Join(m.CAROOT, rootName),
"-alias", m.caUniqueName(),
}
out, err := m.execKeytool(exec.Command(keytoolPath, args...))
fatalIfCmdErr(err, "keytool -importcert", out)
}
func (m *mkcert) uninstallJava() {
args := []string{
"-delete",
"-alias", m.caUniqueName(),
"-keystore", cacertsPath,
"-storepass", storePass,
}
out, err := m.execKeytool(exec.Command(keytoolPath, args...))
if bytes.Contains(out, []byte("does not exist")) {
return // cert didn't exist
}
fatalIfCmdErr(err, "keytool -delete", out)
}
// execKeytool will execute a "keytool" command and if needed re-execute
// the command wrapped in 'sudo' to work around file permissions.
func (m *mkcert) execKeytool(cmd *exec.Cmd) ([]byte, error) {
out, err := cmd.CombinedOutput()
if err != nil && bytes.Contains(out, []byte("java.io.FileNotFoundException")) {
origArgs := cmd.Args[1:]
cmd = exec.Command("sudo", keytoolPath)
cmd.Args = append(cmd.Args, origArgs...)
cmd.Env = []string{
"JAVA_HOME=" + javaHome,
}
out, err = cmd.CombinedOutput()
}
return out, err
}

View File

@@ -15,7 +15,6 @@ import (
) )
var ( var (
FirefoxPath = "/usr/bin/firefox"
FirefoxProfile = os.Getenv("HOME") + "/.mozilla/firefox/*" FirefoxProfile = os.Getenv("HOME") + "/.mozilla/firefox/*"
CertutilInstallHelp = `apt install libnss3-tools" or "yum install nss-tools` CertutilInstallHelp = `apt install libnss3-tools" or "yum install nss-tools`
NSSBrowsers = "Firefox and/or Chrome/Chromium" NSSBrowsers = "Firefox and/or Chrome/Chromium"
@@ -26,12 +25,12 @@ var (
func init() { func init() {
_, err := os.Stat("/etc/pki/ca-trust/source/anchors/") _, err := os.Stat("/etc/pki/ca-trust/source/anchors/")
if !os.IsNotExist(err) { if err == nil {
SystemTrustFilename = "/etc/pki/ca-trust/source/anchors/mkcert-rootCA.pem" SystemTrustFilename = "/etc/pki/ca-trust/source/anchors/mkcert-rootCA.pem"
SystemTrustCommand = []string{"update-ca-trust", "extract"} SystemTrustCommand = []string{"update-ca-trust", "extract"}
} else { } else {
_, err = os.Stat("/usr/local/share/ca-certificates/") _, err = os.Stat("/usr/local/share/ca-certificates/")
if !os.IsNotExist(err) { if err == nil {
SystemTrustFilename = "/usr/local/share/ca-certificates/mkcert-rootCA.crt" SystemTrustFilename = "/usr/local/share/ca-certificates/mkcert-rootCA.crt"
SystemTrustCommand = []string{"update-ca-certificates"} SystemTrustCommand = []string{"update-ca-certificates"}
} }

View File

@@ -17,8 +17,14 @@ var (
) )
func init() { func init() {
_, err := os.Stat(FirefoxPath) for _, path := range []string{
hasNSS = !os.IsNotExist(err) "/usr/bin/firefox", nssDB, "/Applications/Firefox.app",
"/Applications/Firefox Developer Edition.app",
"C:\\Program Files\\Mozilla Firefox",
} {
_, err := os.Stat(path)
hasNSS = hasNSS || err == nil
}
switch runtime.GOOS { switch runtime.GOOS {
case "darwin": case "darwin":
@@ -29,12 +35,10 @@ func init() {
certutilPath = filepath.Join(strings.TrimSpace(string(out)), "bin", "certutil") certutilPath = filepath.Join(strings.TrimSpace(string(out)), "bin", "certutil")
_, err = os.Stat(certutilPath) _, err = os.Stat(certutilPath)
hasCertutil = !os.IsNotExist(err) hasCertutil = err == nil
case "linux": case "linux":
_, err := os.Stat(nssDB) var err error
hasNSS = hasNSS && !os.IsNotExist(err)
certutilPath, err = exec.LookPath("certutil") certutilPath, err = exec.LookPath("certutil")
hasCertutil = err == nil hasCertutil = err == nil
} }
@@ -56,24 +60,21 @@ func (m *mkcert) checkNSS() bool {
return success return success
} }
func (m *mkcert) installNSS() { func (m *mkcert) installNSS() bool {
if m.forEachNSSProfile(func(profile string) { if m.forEachNSSProfile(func(profile string) {
cmd := exec.Command(certutilPath, "-A", "-d", profile, "-t", "C,,", "-n", m.caUniqueName(), "-i", filepath.Join(m.CAROOT, rootName)) cmd := exec.Command(certutilPath, "-A", "-d", profile, "-t", "C,,", "-n", m.caUniqueName(), "-i", filepath.Join(m.CAROOT, rootName))
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("!!! You've hit a known issue. Please report the entire command output at https://github.com/FiloSottile/mkcert/issues/12\nProfile path: %s\nOS: %s/%s\ncertutil: %s\n", profile, runtime.GOOS, runtime.GOARCH, certutilPath)
cmd := exec.Command("ls", "-l", profile[4:])
cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
cmd.Run()
}
fatalIfCmdErr(err, "certutil -A", out) fatalIfCmdErr(err, "certutil -A", out)
}) == 0 { }) == 0 {
log.Printf("ERROR: no %s security databases found", NSSBrowsers) log.Printf("ERROR: no %s security databases found", NSSBrowsers)
return false
} }
if !m.checkNSS() { if !m.checkNSS() {
log.Printf("Installing in %s failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎", NSSBrowsers) log.Printf("Installing in %s failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎", NSSBrowsers)
log.Printf("Note that if you never started %s, you need to do that at least once.", NSSBrowsers) log.Printf("Note that if you never started %s, you need to do that at least once.", NSSBrowsers)
return false
} }
return true
} }
func (m *mkcert) uninstallNSS() { func (m *mkcert) uninstallNSS() {
@@ -90,7 +91,7 @@ func (m *mkcert) uninstallNSS() {
func (m *mkcert) forEachNSSProfile(f func(profile string)) (found int) { func (m *mkcert) forEachNSSProfile(f func(profile string)) (found int) {
profiles, _ := filepath.Glob(FirefoxProfile) profiles, _ := filepath.Glob(FirefoxProfile)
if _, err := os.Stat(nssDB); !os.IsNotExist(err) { if _, err := os.Stat(nssDB); err == nil {
profiles = append(profiles, nssDB) profiles = append(profiles, nssDB)
} }
if len(profiles) == 0 { if len(profiles) == 0 {
@@ -100,13 +101,14 @@ func (m *mkcert) forEachNSSProfile(f func(profile string)) (found int) {
if stat, err := os.Stat(profile); err != nil || !stat.IsDir() { if stat, err := os.Stat(profile); err != nil || !stat.IsDir() {
continue continue
} }
if _, err := os.Stat(filepath.Join(profile, "cert8.db")); !os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(profile, "cert9.db")); err == nil {
f("dbm:" + profile)
found++
}
if _, err := os.Stat(filepath.Join(profile, "cert9.db")); !os.IsNotExist(err) {
f("sql:" + profile) f("sql:" + profile)
found++ found++
continue
}
if _, err := os.Stat(filepath.Join(profile, "cert8.db")); err == nil {
f("dbm:" + profile)
found++
} }
} }
return return

129
truststore_windows.go Normal file
View File

@@ -0,0 +1,129 @@
package main
import (
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"math/big"
"os"
"path/filepath"
"syscall"
"unsafe"
)
var (
FirefoxProfile = os.Getenv("USERPROFILE") + "\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles"
CertutilInstallHelp = "" // certutil unsupported on Windows
NSSBrowsers = "Firefox"
)
var (
modcrypt32 = syscall.NewLazyDLL("crypt32.dll")
procCertAddEncodedCertificateToStore = modcrypt32.NewProc("CertAddEncodedCertificateToStore")
procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
procCertDeleteCertificateFromStore = modcrypt32.NewProc("CertDeleteCertificateFromStore")
procCertDuplicateCertificateContext = modcrypt32.NewProc("CertDuplicateCertificateContext")
procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
)
func (m *mkcert) installPlatform() bool {
// Load cert
cert, err := ioutil.ReadFile(filepath.Join(m.CAROOT, rootName))
fatalIfErr(err, "failed to read root certificate")
// Decode PEM
if certBlock, _ := pem.Decode(cert); certBlock == nil || certBlock.Type != "CERTIFICATE" {
fatalIfErr(fmt.Errorf("Invalid PEM data"), "decode pem")
} else {
cert = certBlock.Bytes
}
// Open root store
store, err := openWindowsRootStore()
fatalIfErr(err, "open root store")
defer store.close()
// Add cert
fatalIfErr(store.addCert(cert), "add cert")
return true
}
func (m *mkcert) uninstallPlatform() bool {
// We'll just remove all certs with the same serial number
// Open root store
store, err := openWindowsRootStore()
fatalIfErr(err, "open root store")
defer store.close()
// Do the deletion
deletedAny, err := store.deleteCertsWithSerial(m.caCert.SerialNumber)
if err == nil && !deletedAny {
err = fmt.Errorf("No certs found")
}
fatalIfErr(err, "delete cert")
return true
}
type windowsRootStore uintptr
func openWindowsRootStore() (windowsRootStore, error) {
store, _, err := procCertOpenSystemStoreW.Call(0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("ROOT"))))
if store != 0 {
return windowsRootStore(store), nil
}
return 0, fmt.Errorf("Failed to open windows root store: %v", err)
}
func (w windowsRootStore) close() error {
ret, _, err := procCertCloseStore.Call(uintptr(w), 0)
if ret != 0 {
return nil
}
return fmt.Errorf("Failed to close windows root store: %v", err)
}
func (w windowsRootStore) addCert(cert []byte) error {
// TODO: ok to always overwrite?
ret, _, err := procCertAddEncodedCertificateToStore.Call(
uintptr(w), // HCERTSTORE hCertStore
uintptr(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING), // DWORD dwCertEncodingType
uintptr(unsafe.Pointer(&cert[0])), // const BYTE *pbCertEncoded
uintptr(len(cert)), // DWORD cbCertEncoded
3, // DWORD dwAddDisposition (CERT_STORE_ADD_REPLACE_EXISTING is 3)
0, // PCCERT_CONTEXT *ppCertContext
)
if ret != 0 {
return nil
}
return fmt.Errorf("Failed adding cert: %v", err)
}
func (w windowsRootStore) deleteCertsWithSerial(serial *big.Int) (bool, error) {
// Go over each, deleting the ones we find
var cert *syscall.CertContext
deletedAny := false
for {
// Next enum
certPtr, _, err := procCertEnumCertificatesInStore.Call(uintptr(w), uintptr(unsafe.Pointer(cert)))
if cert = (*syscall.CertContext)(unsafe.Pointer(certPtr)); cert == nil {
if errno, ok := err.(syscall.Errno); ok && errno == 0x80092004 {
break
}
return deletedAny, fmt.Errorf("Failed enumerating certs: %v", err)
}
// Parse cert
certBytes := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length]
parsedCert, err := x509.ParseCertificate(certBytes)
// We'll just ignore parse failures for now
if err == nil && parsedCert.SerialNumber != nil && parsedCert.SerialNumber.Cmp(serial) == 0 {
// Duplicate the context so it doesn't stop the enum when we delete it
dupCertPtr, _, err := procCertDuplicateCertificateContext.Call(uintptr(unsafe.Pointer(cert)))
if dupCertPtr == 0 {
return deletedAny, fmt.Errorf("Failed duplicating context: %v", err)
}
if ret, _, err := procCertDeleteCertificateFromStore.Call(dupCertPtr); ret == 0 {
return deletedAny, fmt.Errorf("Failed deleting certificate: %v", err)
}
deletedAny = true
}
}
return deletedAny, nil
}

View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/.gitignore generated vendored Normal file
View File

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

28
vendor/software.sslmate.com/src/go-pkcs12/LICENSE generated vendored Normal file
View File

@@ -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.

View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/crypto.go generated vendored Normal file
View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/errors.go generated vendored Normal file
View File

@@ -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)
}

View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/mac.go generated vendored Normal file
View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/pbkdf.go generated vendored Normal file
View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/pkcs12.go generated vendored Normal file
View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/pkcs8.go generated vendored Normal file
View File

@@ -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
vendor/software.sslmate.com/src/go-pkcs12/safebags.go generated vendored Normal file
View File

@@ -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
}