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