-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 3fdc03f
Showing
20 changed files
with
2,079 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Compiled Object files, Static and Dynamic libs (Shared Objects) | ||
*.o | ||
*.a | ||
*.so | ||
|
||
# Folders | ||
_obj | ||
_test | ||
|
||
# Architecture specific extensions/prefixes | ||
*.[568vq] | ||
[568vq].out | ||
|
||
*.cgo1.go | ||
*.cgo2.c | ||
_cgo_defun.c | ||
_cgo_gotypes.go | ||
_cgo_export.* | ||
|
||
_testmain.go | ||
|
||
*.exe | ||
*.test | ||
*.prof |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
sudo: false | ||
|
||
language: go | ||
|
||
before_script: | ||
- go get -u github.com/golang/lint/golint | ||
|
||
script: | ||
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)" | ||
- test -z "$(golint ./... | tee /dev/stderr)" | ||
- go vet ./... | ||
- go test ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2015 Microsoft | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Archived Copy | ||
|
||
This is a clone of Azure's PKCS#12 implementation in Go, originally from | ||
`github.com/Azure/go-pkcs12`. That project has since been retired, in favor of a PKCS#12 | ||
implementation from the Go project itself. However, the official version is read-only, whereas our | ||
projects need to generate `.p12` files. So we have this (unmaintained, but functional) copy. | ||
|
||
Original README content follows. | ||
|
||
|
||
|
||
# Package pkcs12 | ||
|
||
[![GoDoc](https://godoc.org/github.com/Azure/go-pkcs12?status.svg)](https://godoc.org/github.com/Azure/go-pkcs12) | ||
|
||
Package pkcs12 provides some Go implementations of PKCS#12. | ||
|
||
This implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents. | ||
It is intented for decoding P12/PFX-stored certificate+key for use with the crypto/tls package. | ||
|
||
## Example | ||
|
||
```go | ||
p12, err := base64.StdEncoding.DecodeString(`base64-encoded-pfx-file`) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
blocks, err := pkcs12.ConvertToPEM(p12, passwordBytes) | ||
if err != nil { | ||
panic(err) | ||
} | ||
for i := 0; i < len(passwordBytes); i++ { | ||
passwordBytes[i] = 0 // clear password data after use | ||
} | ||
|
||
pemData := []byte{} | ||
for _, b := range blocks { | ||
pemData = append(pemData, pem.EncodeToMemory(b)...) | ||
} | ||
|
||
// then use PEM data for tls to construct tls certificate: | ||
|
||
cert, err := tls.X509KeyPair(pemData, pemData) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
config := tls.Config{ | ||
Certificates: []tls.Certificate{cert}, | ||
} | ||
|
||
// use tls config for http client | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package pkcs12 | ||
|
||
|
||
const ( | ||
TagEndOfContent = 0x00 | ||
TagBoolean = 0x01 | ||
TagInteger = 0x02 | ||
TagBitString = 0x03 | ||
TagOctetString = 0x04 | ||
TagNull = 0x05 | ||
TagOID = 0x06 | ||
TagUTF8String = 0x0C | ||
TagSequence = 0x10 | ||
TagSet = 0x11 | ||
TagPrintableString = 0x13 | ||
TagUTCTime = 0x17 | ||
|
||
ClassUniversal = 0x00 | ||
ClassApplication = 0x40 | ||
ClassContextSpecific = 0x80 | ||
ClassPrivate = 0xC0 | ||
|
||
TypeConstructed = 0x20 | ||
) | ||
|
||
type AsnItem struct { | ||
tag int | ||
sz int | ||
|
||
// if raw is non-nil, item is sealed | ||
raw []byte | ||
|
||
// if content is non-nil, item is primitive type | ||
content []byte | ||
|
||
// if content is nil, item is a container of these: | ||
firstChild *AsnItem | ||
lastChild *AsnItem | ||
|
||
// link for items in container | ||
next *AsnItem | ||
} | ||
|
||
func (a *AsnItem) headersize() int { | ||
if a.sz < 0 { | ||
if a.content != nil { | ||
a.sz = len(a.content) | ||
} else { | ||
a.sz = 0 | ||
for c := a.firstChild; c != nil; c = c.next { | ||
a.sz += c.size() | ||
} | ||
} | ||
} | ||
if a.sz < 128 { | ||
return 2 | ||
} | ||
if a.sz < 256 { | ||
return 3 | ||
} | ||
if a.sz < 65536 { | ||
return 4 | ||
} | ||
// panic? | ||
return -1 | ||
} | ||
|
||
func (a *AsnItem) size() int { | ||
return a.headersize() + a.sz | ||
} | ||
|
||
func (a *AsnItem) write(out []byte) int { | ||
hsz := a.headersize() | ||
if hsz < 0 { | ||
return -1 | ||
} | ||
out[0] = byte(a.tag) | ||
if a.sz < 128 { | ||
out[1] = byte(a.sz) | ||
} else if a.sz < 256 { | ||
out[1] = 0x81 | ||
out[2] = byte(a.sz) | ||
} else if a.sz < 65536 { | ||
out[1] = 0x82 | ||
out[2] = byte(a.sz >> 8) | ||
out[3] = byte(a.sz) | ||
} else { | ||
// unsupported | ||
return -1; | ||
} | ||
out = out[hsz:] | ||
if a.content != nil { | ||
copy(out, a.content) | ||
} else { | ||
for c := a.firstChild; c != nil; c = c.next { | ||
n := c.write(out) | ||
if n < 0 { | ||
return -1 | ||
} | ||
out = out[n:] | ||
} | ||
} | ||
return a.sz + hsz | ||
} | ||
|
||
func (a *AsnItem) append(child *AsnItem) *AsnItem { | ||
// panic if content or >0 size? | ||
if a.lastChild != nil { | ||
a.lastChild.next = child; | ||
} else { | ||
a.firstChild = child; | ||
} | ||
a.lastChild = child; | ||
return child | ||
} | ||
|
||
func AsnNull() *AsnItem { | ||
return &AsnItem{ tag: TagNull, sz: 0 } | ||
} | ||
|
||
func AsnInteger(i int) *AsnItem { | ||
var data []byte = nil | ||
if (i < 0) { | ||
panic("unsupported") | ||
} | ||
if (i < 255) { | ||
data = []byte{ byte(i) } | ||
} else if i < 65535 { | ||
data = []byte{ byte(i >> 8), byte(i & 0xff) } | ||
} else { | ||
panic("unsupported") | ||
} | ||
return &AsnItem{ tag: TagInteger, sz: len(data), content: data } | ||
} | ||
|
||
func AsnContainer(_tag int) *AsnItem { | ||
return &AsnItem{ tag: _tag, sz: -1 } | ||
} | ||
|
||
func AsnSequence() *AsnItem { | ||
return &AsnItem{ tag: TagSequence | TypeConstructed, sz: -1 } | ||
} | ||
|
||
func AsnSet() *AsnItem { | ||
return &AsnItem{ tag: TagSet | TypeConstructed, sz: -1 } | ||
} | ||
|
||
func AsnRaw(_tag int, _data []byte) *AsnItem { | ||
return &AsnItem{ tag: _tag, sz: len(_data), content: _data } | ||
} | ||
|
||
func AsnOID(oid []byte) *AsnItem { | ||
return &AsnItem{ tag: TagOID, sz: len(oid), content: oid } | ||
} | ||
|
||
// Context-Specific Container | ||
func AsnCC(n int) *AsnItem { | ||
return &AsnItem{ | ||
tag: n | ClassContextSpecific | TypeConstructed, | ||
sz: -1, | ||
} | ||
} | ||
|
||
func AsnCCRaw(n int, data []byte) *AsnItem { | ||
return &AsnItem{ | ||
tag: n | ClassContextSpecific, | ||
sz: len(data), content: data, | ||
} | ||
} | ||
|
||
func AsnString(s string) *AsnItem { | ||
b := []byte(s) | ||
a := AsnItem{ tag: TagUTF8String, sz: len(b), content: b } | ||
return &a | ||
} | ||
|
||
func AsnOctetStringContainer() *AsnItem { | ||
return &AsnItem{ tag: TagOctetString, sz: -1 } | ||
} | ||
|
||
func AsnOctetString(data []byte) *AsnItem { | ||
return &AsnItem{ tag: TagOctetString, sz: len(data), content: data } | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package pkcs12 | ||
|
||
import ( | ||
"errors" | ||
"unicode/utf16" | ||
"unicode/utf8" | ||
) | ||
|
||
func bmpString(utf8String []byte) ([]byte, error) { | ||
// References: | ||
// https://tools.ietf.org/html/rfc7292#appendix-B.1 | ||
// http://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. | ||
|
||
rv := make([]byte, 0, 2*len(utf8String)+2) | ||
|
||
start := 0 | ||
for start < len(utf8String) { | ||
c, size := utf8.DecodeRune(utf8String[start:]) | ||
start += size | ||
if t, _ := utf16.EncodeRune(c); t != 0xfffd { | ||
return nil, errors.New("string contains characters that cannot be encoded in UCS-2") | ||
} | ||
rv = append(rv, byte(c/256), byte(c%256)) | ||
} | ||
rv = append(rv, 0, 0) | ||
return rv, nil | ||
} | ||
|
||
func decodeBMPString(bmpString []byte) (string, error) { | ||
if len(bmpString)%2 != 0 { | ||
return "", errors.New("expected BMP byte string to be an even length") | ||
} | ||
|
||
// strip terminator if present | ||
if terminator := bmpString[len(bmpString)-2:]; terminator[0] == terminator[1] && terminator[1] == 0 { | ||
bmpString = bmpString[:len(bmpString)-2] | ||
} | ||
|
||
s := make([]uint16, 0, len(bmpString)/2) | ||
for len(bmpString) > 0 { | ||
s = append(s, uint16(bmpString[0])*265+uint16(bmpString[1])) | ||
bmpString = bmpString[2:] | ||
} | ||
|
||
return string(utf16.Decode(s)), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package pkcs12 | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func TestBMPString(t *testing.T) { | ||
str, err := bmpString([]byte("")) | ||
if bytes.Compare(str, []byte{0, 0}) != 0 { | ||
t.Errorf("expected empty string to return double 0, but found: % x", str) | ||
} | ||
if err != nil { | ||
t.Errorf("err: %v", err) | ||
} | ||
|
||
// Example from https://tools.ietf.org/html/rfc7292#appendix-B | ||
str, err = bmpString([]byte("Beavis")) | ||
if bytes.Compare(str, []byte{0x00, 0x42, 0x00, 0x65, 0x00, 0x61, 0x00, 0x0076, 0x00, 0x69, 0x00, 0x73, 0x00, 0x00}) != 0 { | ||
t.Errorf("expected 'Beavis' to return 0x00 0x42 0x00 0x65 0x00 0x61 0x00 0x76 0x00 0x69 0x00 0x73 0x00 0x00, but found: % x", str) | ||
} | ||
if err != nil { | ||
t.Errorf("err: %v", err) | ||
} | ||
|
||
// some characters from the "Letterlike Symbols Unicode block" | ||
tst := "\u2115 - Double-struck N" | ||
str, err = bmpString([]byte(tst)) | ||
if bytes.Compare(str, []byte{0x21, 0x15, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x20, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x75, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x4e, 0x00, 0x00}) != 0 { | ||
t.Errorf("expected '%s' to return 0x21 0x15 0x00 0x20 0x00 0x2d 0x00 0x20 0x00 0x44 0x00 0x6f 0x00 0x75 0x00 0x62 0x00 0x6c 0x00 0x65 0x00 0x2d 0x00 0x73 0x00 0x74 0x00 0x72 0x00 0x75 0x00 0x63 0x00 0x6b 0x00 0x20 0x00 0x4e 0x00 0x00, but found: % x", tst, str) | ||
} | ||
if err != nil { | ||
t.Errorf("err: %v", err) | ||
} | ||
|
||
// some character outside the BMP should error | ||
tst = "\U0001f000 East wind (Mahjong)" | ||
str, err = bmpString([]byte(tst)) | ||
if err == nil { | ||
t.Errorf("expected '%s' to throw error because the first character is not in the BMP", tst) | ||
} | ||
} |
Oops, something went wrong.