github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/builder/azure/pkcs12/pkcs12.go (about) 1 // Package pkcs12 provides some implementations of PKCS#12. 2 // 3 // This implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents. 4 // It is intended for decoding P12/PFX-stored certificate+key for use with the crypto/tls package. 5 package pkcs12 6 7 import ( 8 "crypto/rand" 9 "crypto/x509/pkix" 10 "encoding/asn1" 11 "errors" 12 "io" 13 ) 14 15 var ( 16 oidLocalKeyID = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 21} 17 oidDataContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1} 18 19 localKeyId = []byte{0x01, 0x00, 0x00, 0x00} 20 ) 21 22 type pfxPdu struct { 23 Version int 24 AuthSafe contentInfo 25 MacData macData `asn1:"optional"` 26 } 27 28 type contentInfo struct { 29 ContentType asn1.ObjectIdentifier 30 Content asn1.RawValue `asn1:"tag:0,explicit,optional"` 31 } 32 33 type encryptedData struct { 34 Version int 35 EncryptedContentInfo encryptedContentInfo 36 } 37 38 type encryptedContentInfo struct { 39 ContentType asn1.ObjectIdentifier 40 ContentEncryptionAlgorithm pkix.AlgorithmIdentifier 41 EncryptedContent []byte `asn1:"tag:0,optional"` 42 } 43 44 func (i encryptedContentInfo) GetAlgorithm() pkix.AlgorithmIdentifier { 45 return i.ContentEncryptionAlgorithm 46 } 47 48 func (i encryptedContentInfo) GetData() []byte { return i.EncryptedContent } 49 50 type safeBag struct { 51 Id asn1.ObjectIdentifier 52 Value asn1.RawValue `asn1:"tag:0,explicit"` 53 Attributes []pkcs12Attribute `asn1:"set,optional"` 54 } 55 56 type pkcs12Attribute struct { 57 Id asn1.ObjectIdentifier 58 Value asn1.RawValue `ans1:"set"` 59 } 60 61 type encryptedPrivateKeyInfo struct { 62 AlgorithmIdentifier pkix.AlgorithmIdentifier 63 EncryptedData []byte 64 } 65 66 func (i encryptedPrivateKeyInfo) GetAlgorithm() pkix.AlgorithmIdentifier { return i.AlgorithmIdentifier } 67 func (i encryptedPrivateKeyInfo) GetData() []byte { return i.EncryptedData } 68 69 // unmarshal calls asn1.Unmarshal, but also returns an error if there is any 70 // trailing data after unmarshaling. 71 func unmarshal(in []byte, out interface{}) error { 72 trailing, err := asn1.Unmarshal(in, out) 73 if err != nil { 74 return err 75 } 76 if len(trailing) != 0 { 77 return errors.New("pkcs12: trailing data found") 78 } 79 return nil 80 } 81 82 func getLocalKeyId(id []byte) (attribute pkcs12Attribute, err error) { 83 octetString := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: id} 84 bytes, err := asn1.Marshal(octetString) 85 if err != nil { 86 return 87 } 88 89 attribute = pkcs12Attribute{ 90 Id: oidLocalKeyID, 91 Value: asn1.RawValue{Tag: 17, Class: 0, IsCompound: true, Bytes: bytes}, 92 } 93 94 return attribute, nil 95 } 96 97 func convertToRawVal(val interface{}) (raw asn1.RawValue, err error) { 98 bytes, err := asn1.Marshal(val) 99 if err != nil { 100 return 101 } 102 103 _, err = asn1.Unmarshal(bytes, &raw) 104 return raw, nil 105 } 106 107 func makeSafeBags(oid asn1.ObjectIdentifier, value []byte) ([]safeBag, error) { 108 attribute, err := getLocalKeyId(localKeyId) 109 110 if err != nil { 111 return nil, EncodeError("local key id: " + err.Error()) 112 } 113 114 bag := make([]safeBag, 1) 115 bag[0] = safeBag{ 116 Id: oid, 117 Value: asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: value}, 118 Attributes: []pkcs12Attribute{attribute}, 119 } 120 121 return bag, nil 122 } 123 124 func makeCertBagContentInfo(derBytes []byte) (*contentInfo, error) { 125 certBag1 := certBag{ 126 Id: oidCertTypeX509Certificate, 127 Data: derBytes, 128 } 129 130 bytes, err := asn1.Marshal(certBag1) 131 if err != nil { 132 return nil, EncodeError("encoding cert bag: " + err.Error()) 133 } 134 135 certSafeBags, err := makeSafeBags(oidCertBagType, bytes) 136 if err != nil { 137 return nil, EncodeError("safe bags: " + err.Error()) 138 } 139 140 return makeContentInfo(certSafeBags) 141 } 142 143 func makeShroudedKeyBagContentInfo(privateKey interface{}, password []byte) (*contentInfo, error) { 144 shroudedKeyBagBytes, err := encodePkcs8ShroudedKeyBag(privateKey, password) 145 if err != nil { 146 return nil, EncodeError("encode PKCS#8 shrouded key bag: " + err.Error()) 147 } 148 149 safeBags, err := makeSafeBags(oidPkcs8ShroudedKeyBagType, shroudedKeyBagBytes) 150 if err != nil { 151 return nil, EncodeError("safe bags: " + err.Error()) 152 } 153 154 return makeContentInfo(safeBags) 155 } 156 157 func makeContentInfo(val interface{}) (*contentInfo, error) { 158 fullBytes, err := asn1.Marshal(val) 159 if err != nil { 160 return nil, EncodeError("contentInfo raw value marshal: " + err.Error()) 161 } 162 163 octetStringVal := asn1.RawValue{Tag: 4, Class: 0, IsCompound: false, Bytes: fullBytes} 164 octetStringFullBytes, err := asn1.Marshal(octetStringVal) 165 if err != nil { 166 return nil, EncodeError("raw contentInfo to octet string: " + err.Error()) 167 } 168 169 contentInfo := contentInfo{ContentType: oidDataContentType} 170 contentInfo.Content = asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: octetStringFullBytes} 171 172 return &contentInfo, nil 173 } 174 175 func makeContentInfos(derBytes []byte, privateKey interface{}, password []byte) ([]contentInfo, error) { 176 shroudedKeyContentInfo, err := makeShroudedKeyBagContentInfo(privateKey, password) 177 if err != nil { 178 return nil, EncodeError("shrouded key content info: " + err.Error()) 179 } 180 181 certBagContentInfo, err := makeCertBagContentInfo(derBytes) 182 if err != nil { 183 return nil, EncodeError("cert bag content info: " + err.Error()) 184 } 185 186 contentInfos := make([]contentInfo, 2) 187 contentInfos[0] = *shroudedKeyContentInfo 188 contentInfos[1] = *certBagContentInfo 189 190 return contentInfos, nil 191 } 192 193 func makeSalt(saltByteCount int) ([]byte, error) { 194 salt := make([]byte, saltByteCount) 195 _, err := io.ReadFull(rand.Reader, salt) 196 return salt, err 197 } 198 199 // Encode converts a certificate and a private key to the PKCS#12 byte stream format. 200 // 201 // derBytes is a DER encoded certificate. 202 // privateKey is an RSA 203 func Encode(derBytes []byte, privateKey interface{}, password string) ([]byte, error) { 204 secret, err := bmpString(password) 205 if err != nil { 206 return nil, ErrIncorrectPassword 207 } 208 209 contentInfos, err := makeContentInfos(derBytes, privateKey, secret) 210 if err != nil { 211 return nil, err 212 } 213 214 // Marhsal []contentInfo so we can re-constitute the byte stream that will 215 // be suitable for computing the MAC 216 bytes, err := asn1.Marshal(contentInfos) 217 if err != nil { 218 return nil, err 219 } 220 221 // Unmarshal as an asn1.RawValue so, we can compute the MAC against the .Bytes 222 var contentInfosRaw asn1.RawValue 223 err = unmarshal(bytes, &contentInfosRaw) 224 if err != nil { 225 return nil, err 226 } 227 228 authSafeContentInfo, err := makeContentInfo(contentInfosRaw) 229 if err != nil { 230 return nil, EncodeError("authSafe content info: " + err.Error()) 231 } 232 233 salt, err := makeSalt(pbeSaltSizeBytes) 234 if err != nil { 235 return nil, EncodeError("salt value: " + err.Error()) 236 } 237 238 // Compute the MAC for marshaled bytes of contentInfos, which includes the 239 // cert bag, and the shrouded key bag. 240 digest := computeMac(contentInfosRaw.FullBytes, pbeIterationCount, salt, secret) 241 242 pfx := pfxPdu{ 243 Version: 3, 244 AuthSafe: *authSafeContentInfo, 245 MacData: macData{ 246 Iterations: pbeIterationCount, 247 MacSalt: salt, 248 Mac: digestInfo{ 249 Algorithm: pkix.AlgorithmIdentifier{ 250 Algorithm: oidSha1Algorithm, 251 }, 252 Digest: digest, 253 }, 254 }, 255 } 256 257 bytes, err = asn1.Marshal(pfx) 258 if err != nil { 259 return nil, EncodeError("marshal PFX PDU: " + err.Error()) 260 } 261 262 return bytes, err 263 }