github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/src/golang.org/x/crypto/pkcs12/pkcs12.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package pkcs12 implements some of PKCS#12. 6 // 7 // This implementation is distilled from https://tools.ietf.org/html/rfc7292 8 // and referenced documents. It is intended for decoding P12/PFX-stored 9 // certificates and keys for use with the crypto/tls package. 10 package pkcs12 11 12 import ( 13 "crypto/ecdsa" 14 "crypto/rsa" 15 "crypto/x509" 16 "crypto/x509/pkix" 17 "encoding/asn1" 18 "encoding/hex" 19 "encoding/pem" 20 "errors" 21 ) 22 23 var ( 24 oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1}) 25 oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6}) 26 27 oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20}) 28 oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21}) 29 oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1}) 30 ) 31 32 type pfxPdu struct { 33 Version int 34 AuthSafe contentInfo 35 MacData macData `asn1:"optional"` 36 } 37 38 type contentInfo struct { 39 ContentType asn1.ObjectIdentifier 40 Content asn1.RawValue `asn1:"tag:0,explicit,optional"` 41 } 42 43 type encryptedData struct { 44 Version int 45 EncryptedContentInfo encryptedContentInfo 46 } 47 48 type encryptedContentInfo struct { 49 ContentType asn1.ObjectIdentifier 50 ContentEncryptionAlgorithm pkix.AlgorithmIdentifier 51 EncryptedContent []byte `asn1:"tag:0,optional"` 52 } 53 54 func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier { 55 return i.ContentEncryptionAlgorithm 56 } 57 58 func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent } 59 60 type safeBag struct { 61 Id asn1.ObjectIdentifier 62 Value asn1.RawValue `asn1:"tag:0,explicit"` 63 Attributes []pkcs12Attribute `asn1:"set,optional"` 64 } 65 66 type pkcs12Attribute struct { 67 Id asn1.ObjectIdentifier 68 Value asn1.RawValue `asn1:"set"` 69 } 70 71 type encryptedPrivateKeyInfo struct { 72 AlgorithmIdentifier pkix.AlgorithmIdentifier 73 EncryptedData []byte 74 } 75 76 func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier { 77 return i.AlgorithmIdentifier 78 } 79 80 func (i encryptedPrivateKeyInfo) Data() []byte { 81 return i.EncryptedData 82 } 83 84 // PEM block types 85 const ( 86 certificateType = "CERTIFICATE" 87 privateKeyType = "PRIVATE KEY" 88 ) 89 90 // unmarshal calls asn1.Unmarshal, but also returns an error if there is any 91 // trailing data after unmarshaling. 92 func unmarshal(in []byte, out interface{}) error { 93 trailing, err := asn1.Unmarshal(in, out) 94 if err != nil { 95 return err 96 } 97 if len(trailing) != 0 { 98 return errors.New("pkcs12: trailing data found") 99 } 100 return nil 101 } 102 103 // ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks. 104 func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) { 105 encodedPassword, err := bmpString(password) 106 if err != nil { 107 return nil, ErrIncorrectPassword 108 } 109 110 bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword) 111 112 blocks := make([]*pem.Block, 0, len(bags)) 113 for _, bag := range bags { 114 block, err := convertBag(&bag, encodedPassword) 115 if err != nil { 116 return nil, err 117 } 118 blocks = append(blocks, block) 119 } 120 121 return blocks, nil 122 } 123 124 func convertBag(bag *safeBag, password []byte) (*pem.Block, error) { 125 block := &pem.Block{ 126 Headers: make(map[string]string), 127 } 128 129 for _, attribute := range bag.Attributes { 130 k, v, err := convertAttribute(&attribute) 131 if err != nil { 132 return nil, err 133 } 134 block.Headers[k] = v 135 } 136 137 switch { 138 case bag.Id.Equal(oidCertBag): 139 block.Type = certificateType 140 certsData, err := decodeCertBag(bag.Value.Bytes) 141 if err != nil { 142 return nil, err 143 } 144 block.Bytes = certsData 145 case bag.Id.Equal(oidPKCS8ShroundedKeyBag): 146 block.Type = privateKeyType 147 148 key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password) 149 if err != nil { 150 return nil, err 151 } 152 153 switch key := key.(type) { 154 case *rsa.PrivateKey: 155 block.Bytes = x509.MarshalPKCS1PrivateKey(key) 156 case *ecdsa.PrivateKey: 157 block.Bytes, err = x509.MarshalECPrivateKey(key) 158 if err != nil { 159 return nil, err 160 } 161 default: 162 return nil, errors.New("found unknown private key type in PKCS#8 wrapping") 163 } 164 default: 165 return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String()) 166 } 167 return block, nil 168 } 169 170 func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) { 171 isString := false 172 173 switch { 174 case attribute.Id.Equal(oidFriendlyName): 175 key = "friendlyName" 176 isString = true 177 case attribute.Id.Equal(oidLocalKeyID): 178 key = "localKeyId" 179 case attribute.Id.Equal(oidMicrosoftCSPName): 180 // This key is chosen to match OpenSSL. 181 key = "Microsoft CSP Name" 182 isString = true 183 default: 184 return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String()) 185 } 186 187 if isString { 188 if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil { 189 return "", "", err 190 } 191 if value, err = decodeBMPString(attribute.Value.Bytes); err != nil { 192 return "", "", err 193 } 194 } else { 195 var id []byte 196 if err := unmarshal(attribute.Value.Bytes, &id); err != nil { 197 return "", "", err 198 } 199 value = hex.EncodeToString(id) 200 } 201 202 return key, value, nil 203 } 204 205 // Decode extracts a certificate and private key from pfxData. This function 206 // assumes that there is only one certificate and only one private key in the 207 // pfxData. 208 func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) { 209 encodedPassword, err := bmpString(password) 210 if err != nil { 211 return nil, nil, err 212 } 213 214 bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword) 215 if err != nil { 216 return nil, nil, err 217 } 218 219 // if len(bags) != 2 { 220 // err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU") 221 // return 222 // } 223 224 for _, bag := range bags { 225 switch { 226 case bag.Id.Equal(oidCertBag): 227 if certificate != nil { 228 err = errors.New("pkcs12: expected exactly one certificate bag") 229 } 230 231 certsData, err := decodeCertBag(bag.Value.Bytes) 232 if err != nil { 233 return nil, nil, err 234 } 235 certs, err := x509.ParseCertificates(certsData) 236 if err != nil { 237 return nil, nil, err 238 } 239 if len(certs) != 1 { 240 err = errors.New("pkcs12: expected exactly one certificate in the certBag") 241 return nil, nil, err 242 } 243 certificate = certs[0] 244 245 case bag.Id.Equal(oidPKCS8ShroundedKeyBag): 246 if privateKey != nil { 247 err = errors.New("pkcs12: expected exactly one key bag") 248 } 249 250 if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil { 251 return nil, nil, err 252 } 253 } 254 } 255 256 if certificate == nil { 257 return nil, nil, errors.New("pkcs12: certificate missing") 258 } 259 if privateKey == nil { 260 return nil, nil, errors.New("pkcs12: private key missing") 261 } 262 263 return 264 } 265 266 func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) { 267 pfx := new(pfxPdu) 268 if err := unmarshal(p12Data, pfx); err != nil { 269 return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error()) 270 } 271 272 if pfx.Version != 3 { 273 return nil, nil, NotImplementedError("can only decode v3 PFX PDU's") 274 } 275 276 if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) { 277 return nil, nil, NotImplementedError("only password-protected PFX is implemented") 278 } 279 280 // unmarshal the explicit bytes in the content for type 'data' 281 if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil { 282 return nil, nil, err 283 } 284 285 if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 { 286 return nil, nil, errors.New("pkcs12: no MAC in data") 287 } 288 289 if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil { 290 if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 { 291 // some implementations use an empty byte array 292 // for the empty string password try one more 293 // time with empty-empty password 294 password = nil 295 err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password) 296 } 297 if err != nil { 298 return nil, nil, err 299 } 300 } 301 302 var authenticatedSafe []contentInfo 303 if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil { 304 return nil, nil, err 305 } 306 307 if len(authenticatedSafe) != 2 { 308 return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe") 309 } 310 311 for _, ci := range authenticatedSafe { 312 var data []byte 313 314 switch { 315 case ci.ContentType.Equal(oidDataContentType): 316 if err := unmarshal(ci.Content.Bytes, &data); err != nil { 317 return nil, nil, err 318 } 319 case ci.ContentType.Equal(oidEncryptedDataContentType): 320 var encryptedData encryptedData 321 if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil { 322 return nil, nil, err 323 } 324 if encryptedData.Version != 0 { 325 return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported") 326 } 327 if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil { 328 return nil, nil, err 329 } 330 default: 331 return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe") 332 } 333 334 var safeContents []safeBag 335 if err := unmarshal(data, &safeContents); err != nil { 336 return nil, nil, err 337 } 338 bags = append(bags, safeContents...) 339 } 340 341 return bags, password, nil 342 }