Skip to content

Commit

Permalink
Migration deprecated repository
Browse files Browse the repository at this point in the history
  • Loading branch information
binlab committed Aug 15, 2020
0 parents commit 3fdc03f
Show file tree
Hide file tree
Showing 20 changed files with 2,079 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .gitignore
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
12 changes: 12 additions & 0 deletions .travis.yml
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 ./...
21 changes: 21 additions & 0 deletions LICENSE
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.
54 changes: 54 additions & 0 deletions README.md
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
```
185 changes: 185 additions & 0 deletions asn1.go
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 }
}


49 changes: 49 additions & 0 deletions bmp-string.go
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
}
42 changes: 42 additions & 0 deletions bmp-string_test.go
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)
}
}

0 comments on commit 3fdc03f

Please sign in to comment.