gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/x509/certinfo.go (about) 1 package x509 2 3 import ( 4 "bytes" 5 "crypto/ecdsa" 6 "crypto/rsa" 7 "crypto/x509/pkix" 8 "encoding/asn1" 9 "encoding/binary" 10 "errors" 11 "fmt" 12 "gitee.com/ks-custle/core-gm/ecdsa_ext" 13 "math/big" 14 "net" 15 16 "gitee.com/ks-custle/core-gm/sm2" 17 ) 18 19 // Extra ASN1 OIDs that we may need to handle 20 var ( 21 oidEmailAddress = []int{1, 2, 840, 113549, 1, 9, 1} 22 oidNSComment = []int{2, 16, 840, 1, 113730, 1, 13} 23 ) 24 25 // tbsCertificate allows unmarshaling of the "To-Be-Signed" principle portion 26 // of the certificate 27 // type tbsCertificate struct { 28 // Version int `asn1:"optional,explicit,default:1,tag:0"` 29 // SerialNumber *big.Int 30 // SignatureAlgorithm pkix.AlgorithmIdentifier 31 // Issuer asn1.RawValue 32 // Validity validity 33 // Subject asn1.RawValue 34 // PublicKey publicKeyInfo 35 // UniqueID asn1.BitString `asn1:"optional,tag:1"` 36 // SubjectUniqueID asn1.BitString `asn1:"optional,tag:2"` 37 // Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"` 38 // } 39 40 // certUniqueIDs extracts the subject and issuer unique IDs which are 41 // byte strings. These are not common but may be present in x509v2 certificates 42 // or later under tags 1 and 2 (before x509v3 extensions). 43 func certUniqueIDs(tbsAsnData []byte) (issuerUniqueID, subjectUniqueID []byte, err error) { 44 var tbs tbsCertificate 45 rest, err := asn1.Unmarshal(tbsAsnData, &tbs) 46 if err != nil { 47 return nil, nil, err 48 } 49 if len(rest) > 0 { 50 return nil, nil, asn1.SyntaxError{Msg: "trailing data"} 51 } 52 iuid := tbs.UniqueId.RightAlign() 53 suid := tbs.SubjectUniqueId.RightAlign() 54 return iuid, suid, err 55 } 56 57 // printName prints the fields of a distinguished name, which include such 58 // things as its common name and locality. 59 func printName(names []pkix.AttributeTypeAndValue, buf *bytes.Buffer) []string { 60 var values []string 61 for _, name := range names { 62 oid := name.Type 63 if len(oid) == 4 && oid[0] == 2 && oid[1] == 5 && oid[2] == 4 { 64 switch oid[3] { 65 case 3: 66 values = append(values, fmt.Sprintf("CN=%s", name.Value)) 67 case 6: 68 values = append(values, fmt.Sprintf("C=%s", name.Value)) 69 case 7: 70 values = append(values, fmt.Sprintf("L=%s", name.Value)) 71 case 8: 72 values = append(values, fmt.Sprintf("ST=%s", name.Value)) 73 case 10: 74 values = append(values, fmt.Sprintf("O=%s", name.Value)) 75 case 11: 76 values = append(values, fmt.Sprintf("OU=%s", name.Value)) 77 default: 78 values = append(values, fmt.Sprintf("UnknownOID=%s", name.Type.String())) 79 } 80 } else if oid.Equal(oidEmailAddress) { 81 values = append(values, fmt.Sprintf("emailAddress=%s", name.Value)) 82 } else { 83 values = append(values, fmt.Sprintf("UnknownOID=%s", name.Type.String())) 84 } 85 } 86 if len(values) > 0 { 87 buf.WriteString(values[0]) 88 for i := 1; i < len(values); i++ { 89 buf.WriteString("," + values[i]) 90 } 91 buf.WriteString("\n") 92 } 93 return values 94 } 95 96 // dsaKeyPrinter formats the Y, P, Q, or G components of a DSA public key. 97 func dsaKeyPrinter(name string, val *big.Int, buf *bytes.Buffer) { 98 buf.WriteString(fmt.Sprintf("%16s%s:", "", name)) 99 for i, b := range val.Bytes() { 100 if (i % 15) == 0 { 101 buf.WriteString(fmt.Sprintf("\n%20s", "")) 102 } 103 buf.WriteString(fmt.Sprintf("%02x", b)) 104 if i != len(val.Bytes())-1 { 105 buf.WriteString(":") 106 } 107 } 108 buf.WriteString("\n") 109 } 110 111 func printVersion(version int, buf *bytes.Buffer) { 112 hexVersion := version - 1 113 if hexVersion < 0 { 114 hexVersion = 0 115 } 116 buf.WriteString(fmt.Sprintf("%8sVersion: %d (%#x)\n", "", version, hexVersion)) 117 } 118 119 func printSubjectInformation(subj *pkix.Name, pkAlgo PublicKeyAlgorithm, pk interface{}, buf *bytes.Buffer) error { 120 buf.WriteString(fmt.Sprintf("%8sSubject: ", "")) 121 printName(subj.Names, buf) 122 buf.WriteString(fmt.Sprintf("%8sSubject Public Key Info:\n%12sPublic Key Algorithm: ", "", "")) 123 switch pkAlgo { 124 case SM2: 125 buf.WriteString("SM2\n") 126 if sm2Key, ok := pk.(*sm2.PublicKey); ok { 127 buf.WriteString(fmt.Sprintf("%16sPublic-Key: (%d bit)\n", "", sm2Key.Params().BitSize)) 128 dsaKeyPrinter("X", sm2Key.X, buf) 129 dsaKeyPrinter("Y", sm2Key.Y, buf) 130 buf.WriteString(fmt.Sprintf("%16sCurve: %s\n", "", sm2Key.Params().Name)) 131 } else { 132 return errors.New("certinfo: Expected sm2.PublicKey for type x509.SM2") 133 } 134 case RSA: 135 buf.WriteString("RSA\n") 136 if rsaKey, ok := pk.(*rsa.PublicKey); ok { 137 buf.WriteString(fmt.Sprintf("%16sPublic-Key: (%d bit)\n", "", rsaKey.N.BitLen())) 138 // Some implementations (notably OpenSSL) prepend 0x00 to the modulus 139 // if its most-significant bit is set. There is no need to do that here 140 // because the modulus is always unsigned and the extra byte can be 141 // confusing given the bit length. 142 buf.WriteString(fmt.Sprintf("%16sModulus:", "")) 143 for i, val := range rsaKey.N.Bytes() { 144 if (i % 15) == 0 { 145 buf.WriteString(fmt.Sprintf("\n%20s", "")) 146 } 147 buf.WriteString(fmt.Sprintf("%02x", val)) 148 if i != len(rsaKey.N.Bytes())-1 { 149 buf.WriteString(":") 150 } 151 } 152 buf.WriteString(fmt.Sprintf("\n%16sExponent: %d (%#x)\n", "", rsaKey.E, rsaKey.E)) 153 } else { 154 return errors.New("certinfo: Expected rsa.PublicKey for type x509.RSA") 155 } 156 // case DSA: 157 // buf.WriteString(fmt.Sprintf("DSA\n")) 158 // if dsaKey, ok := pk.(*dsa.PublicKey); ok { 159 // dsaKeyPrinter("pub", dsaKey.Y, buf) 160 // dsaKeyPrinter("P", dsaKey.P, buf) 161 // dsaKeyPrinter("Q", dsaKey.Q, buf) 162 // dsaKeyPrinter("G", dsaKey.G, buf) 163 // } else { 164 // return errors.New("certinfo: Expected dsa.PublicKey for type x509.DSA") 165 // } 166 case ECDSA: 167 buf.WriteString("ECDSA\n") 168 if ecdsaKey, ok := pk.(*ecdsa.PublicKey); ok { 169 buf.WriteString(fmt.Sprintf("%16sPublic-Key: (%d bit)\n", "", ecdsaKey.Params().BitSize)) 170 dsaKeyPrinter("X", ecdsaKey.X, buf) 171 dsaKeyPrinter("Y", ecdsaKey.Y, buf) 172 buf.WriteString(fmt.Sprintf("%16sCurve: %s\n", "", ecdsaKey.Params().Name)) 173 } else { 174 return errors.New("certinfo: Expected ecdsa.PublicKey for type x509.DSA") 175 } 176 case ECDSAEXT: 177 buf.WriteString("ECDSAEXT\n") 178 if ecdsaKey, ok := pk.(*ecdsa_ext.PublicKey); ok { 179 buf.WriteString(fmt.Sprintf("%16sPublic-Key: (%d bit)\n", "", ecdsaKey.Params().BitSize)) 180 dsaKeyPrinter("X", ecdsaKey.X, buf) 181 dsaKeyPrinter("Y", ecdsaKey.Y, buf) 182 buf.WriteString(fmt.Sprintf("%16sCurve: %s\n", "", ecdsaKey.Params().Name)) 183 } else { 184 return errors.New("certinfo: Expected ecdsa.PublicKey for type x509.DSA") 185 } 186 default: 187 return errors.New("certinfo: Unknown public key type") 188 } 189 return nil 190 } 191 192 func printSubjKeyId(ext pkix.Extension, buf *bytes.Buffer) error { 193 // subjectKeyIdentifier: RFC 5280, 4.2.1.2 194 buf.WriteString(fmt.Sprintf("%12sX509v3 Subject Key Identifier:", "")) 195 if ext.Critical { 196 buf.WriteString(" critical\n") 197 } else { 198 buf.WriteString("\n") 199 } 200 var subjectKeyId []byte 201 if _, err := asn1.Unmarshal(ext.Value, &subjectKeyId); err != nil { 202 return err 203 } 204 for i := 0; i < len(subjectKeyId); i++ { 205 if i == 0 { 206 buf.WriteString(fmt.Sprintf("%16s%02X", "", subjectKeyId[0])) 207 } else { 208 buf.WriteString(fmt.Sprintf(":%02X", subjectKeyId[i])) 209 } 210 } 211 buf.WriteString("\n") 212 return nil 213 } 214 215 func printSubjAltNames(ext pkix.Extension, dnsNames []string, emailAddresses []string, ipAddresses []net.IP, buf *bytes.Buffer) error { 216 // subjectAltName: RFC 5280, 4.2.1.6 217 // TODO: Currently crypto/x509 only extracts DNS, email, and IP addresses. 218 // We should add the others to it or implement them here. 219 buf.WriteString(fmt.Sprintf("%12sX509v3 Subject Alternative Name:", "")) 220 if ext.Critical { 221 buf.WriteString(" critical\n") 222 } else { 223 buf.WriteString("\n") 224 } 225 if len(dnsNames) > 0 { 226 buf.WriteString(fmt.Sprintf("%16sDNS:%s", "", dnsNames[0])) 227 for i := 1; i < len(dnsNames); i++ { 228 buf.WriteString(fmt.Sprintf(", DNS:%s", dnsNames[i])) 229 } 230 buf.WriteString("\n") 231 } 232 if len(emailAddresses) > 0 { 233 buf.WriteString(fmt.Sprintf("%16semail:%s", "", emailAddresses[0])) 234 for i := 1; i < len(emailAddresses); i++ { 235 buf.WriteString(fmt.Sprintf(", email:%s", emailAddresses[i])) 236 } 237 buf.WriteString("\n") 238 } 239 if len(ipAddresses) > 0 { 240 buf.WriteString(fmt.Sprintf("%16sIP Address:%s", "", ipAddresses[0].String())) // XXX verify string format 241 for i := 1; i < len(ipAddresses); i++ { 242 buf.WriteString(fmt.Sprintf(", IP Address:%s", ipAddresses[i].String())) 243 } 244 buf.WriteString("\n") 245 } 246 return nil 247 } 248 249 func printSignature(sigAlgo SignatureAlgorithm, sig []byte, buf *bytes.Buffer) { 250 buf.WriteString(fmt.Sprintf("%4sSignature Algorithm: %s", "", sigAlgo)) 251 for i, val := range sig { 252 if (i % 18) == 0 { 253 buf.WriteString(fmt.Sprintf("\n%9s", "")) 254 } 255 buf.WriteString(fmt.Sprintf("%02x", val)) 256 if i != len(sig)-1 { 257 buf.WriteString(":") 258 } 259 } 260 buf.WriteString("\n") 261 } 262 263 // CertificateText returns a human-readable string representation 264 // of the certificate cert. The format is similar (but not identical) 265 // to the OpenSSL way of printing certificates. 266 func CertificateText(cert *Certificate) (string, error) { 267 var buf bytes.Buffer 268 buf.Grow(4096) // 4KiB should be enough 269 270 buf.WriteString(fmt.Sprintf("Certificate:\n")) 271 buf.WriteString(fmt.Sprintf("%4sData:\n", "")) 272 printVersion(cert.Version, &buf) 273 buf.WriteString(fmt.Sprintf("%8sSerial Number: %d (%#x)\n", "", cert.SerialNumber, cert.SerialNumber)) 274 buf.WriteString(fmt.Sprintf("%4sSignature Algorithm: %s\n", "", cert.SignatureAlgorithm)) 275 276 // Issuer information 277 buf.WriteString(fmt.Sprintf("%8sIssuer: ", "")) 278 printName(cert.Issuer.Names, &buf) 279 280 // Validity information 281 buf.WriteString(fmt.Sprintf("%8sValidity\n", "")) 282 buf.WriteString(fmt.Sprintf("%12sNot Before: %s\n", "", cert.NotBefore.Format("2006/01/02 15:04:05"))) 283 buf.WriteString(fmt.Sprintf("%12sNot After : %s\n", "", cert.NotAfter.Format("2006/01/02 15:04:05"))) 284 285 // Subject information 286 err := printSubjectInformation(&cert.Subject, cert.PublicKeyAlgorithm, cert.PublicKey, &buf) 287 if err != nil { 288 return "", err 289 } 290 291 // Issuer/Subject Unique ID, typically used in old v2 certificates 292 issuerUID, subjectUID, err := certUniqueIDs(cert.RawTBSCertificate) 293 if err != nil { 294 return "", errors.New(fmt.Sprintf("certinfo: Error parsing TBS unique attributes: %s\n", err.Error())) 295 } 296 if len(issuerUID) > 0 { 297 buf.WriteString(fmt.Sprintf("%8sIssuer Unique ID: %02x", "", issuerUID[0])) 298 for i := 1; i < len(issuerUID); i++ { 299 buf.WriteString(fmt.Sprintf(":%02x", issuerUID[i])) 300 } 301 buf.WriteString("\n") 302 } 303 if len(subjectUID) > 0 { 304 buf.WriteString(fmt.Sprintf("%8sSubject Unique ID: %02x", "", subjectUID[0])) 305 for i := 1; i < len(subjectUID); i++ { 306 buf.WriteString(fmt.Sprintf(":%02x", subjectUID[i])) 307 } 308 buf.WriteString("\n") 309 } 310 311 // Optional extensions for X509v3 312 if cert.Version == 3 && len(cert.Extensions) > 0 { 313 buf.WriteString(fmt.Sprintf("%8sX509v3 extensions:\n", "")) 314 for _, ext := range cert.Extensions { 315 if len(ext.Id) == 4 && ext.Id[0] == 2 && ext.Id[1] == 5 && ext.Id[2] == 29 { 316 switch ext.Id[3] { 317 case 14: 318 err = printSubjKeyId(ext, &buf) 319 case 15: 320 // keyUsage: RFC 5280, 4.2.1.3 321 buf.WriteString(fmt.Sprintf("%12sX509v3 Key Usage:", "")) 322 if ext.Critical { 323 buf.WriteString(" critical\n") 324 } else { 325 buf.WriteString("\n") 326 } 327 var usages []string 328 if cert.KeyUsage&KeyUsageDigitalSignature > 0 { 329 usages = append(usages, "Digital Signature") 330 } 331 if cert.KeyUsage&KeyUsageContentCommitment > 0 { 332 usages = append(usages, "Content Commitment") 333 } 334 if cert.KeyUsage&KeyUsageKeyEncipherment > 0 { 335 usages = append(usages, "Key Encipherment") 336 } 337 if cert.KeyUsage&KeyUsageDataEncipherment > 0 { 338 usages = append(usages, "Data Encipherment") 339 } 340 if cert.KeyUsage&KeyUsageKeyAgreement > 0 { 341 usages = append(usages, "Key Agreement") 342 } 343 if cert.KeyUsage&KeyUsageCertSign > 0 { 344 usages = append(usages, "Certificate Sign") 345 } 346 if cert.KeyUsage&KeyUsageCRLSign > 0 { 347 usages = append(usages, "CRL Sign") 348 } 349 if cert.KeyUsage&KeyUsageEncipherOnly > 0 { 350 usages = append(usages, "Encipher Only") 351 } 352 if cert.KeyUsage&KeyUsageDecipherOnly > 0 { 353 usages = append(usages, "Decipher Only") 354 } 355 if len(usages) > 0 { 356 buf.WriteString(fmt.Sprintf("%16s%s", "", usages[0])) 357 for i := 1; i < len(usages); i++ { 358 buf.WriteString(fmt.Sprintf(", %s", usages[i])) 359 } 360 buf.WriteString("\n") 361 } else { 362 buf.WriteString(fmt.Sprintf("%16sNone\n", "")) 363 } 364 case 17: 365 err = printSubjAltNames(ext, cert.DNSNames, cert.EmailAddresses, cert.IPAddresses, &buf) 366 case 19: 367 // basicConstraints: RFC 5280, 4.2.1.9 368 if !cert.BasicConstraintsValid { 369 break 370 } 371 buf.WriteString(fmt.Sprintf("%12sX509v3 Basic Constraints:", "")) 372 if ext.Critical { 373 buf.WriteString(" critical\n") 374 } else { 375 buf.WriteString("\n") 376 } 377 if cert.IsCA { 378 buf.WriteString(fmt.Sprintf("%16sCA:TRUE", "")) 379 } else { 380 buf.WriteString(fmt.Sprintf("%16sCA:FALSE", "")) 381 } 382 if cert.MaxPathLenZero { 383 buf.WriteString(fmt.Sprintf(", pathlen:0\n")) 384 } else if cert.MaxPathLen > 0 { 385 buf.WriteString(fmt.Sprintf(", pathlen:%d\n", cert.MaxPathLen)) 386 } else { 387 buf.WriteString("\n") 388 } 389 case 30: 390 // nameConstraints: RFC 5280, 4.2.1.10 391 // TODO: Currently crypto/x509 only supports "Permitted" and not "Excluded" 392 // subtrees. Furthermore it assumes all types are DNS names which is not 393 // necessarily true. This missing functionality should be implemented. 394 buf.WriteString(fmt.Sprintf("%12sX509v3 Name Constraints:", "")) 395 if ext.Critical { 396 buf.WriteString(" critical\n") 397 } else { 398 buf.WriteString("\n") 399 } 400 if len(cert.PermittedDNSDomains) > 0 { 401 buf.WriteString(fmt.Sprintf("%16sPermitted:\n%18s%s", "", "", cert.PermittedDNSDomains[0])) 402 for i := 1; i < len(cert.PermittedDNSDomains); i++ { 403 buf.WriteString(fmt.Sprintf(", %s", cert.PermittedDNSDomains[i])) 404 } 405 buf.WriteString("\n") 406 } 407 case 31: 408 // CRLDistributionPoints: RFC 5280, 4.2.1.13 409 // TODO: Currently crypto/x509 does not fully implement this section, 410 // including types and reason flags. 411 buf.WriteString(fmt.Sprintf("%12sX509v3 CRL Distribution Points:", "")) 412 if ext.Critical { 413 buf.WriteString(" critical\n") 414 } else { 415 buf.WriteString("\n") 416 } 417 if len(cert.CRLDistributionPoints) > 0 { 418 buf.WriteString(fmt.Sprintf("\n%16sFull Name:\n%18sURI:%s", "", "", cert.CRLDistributionPoints[0])) 419 for i := 1; i < len(cert.CRLDistributionPoints); i++ { 420 buf.WriteString(fmt.Sprintf(", URI:%s", cert.CRLDistributionPoints[i])) 421 } 422 buf.WriteString("\n\n") 423 } 424 case 32: 425 // certificatePoliciesExt: RFC 5280, 4.2.1.4 426 // TODO: Currently crypto/x509 does not fully impelment this section, 427 // including the Certification Practice Statement (CPS) 428 buf.WriteString(fmt.Sprintf("%12sX509v3 Certificate Policies:", "")) 429 if ext.Critical { 430 buf.WriteString(" critical\n") 431 } else { 432 buf.WriteString("\n") 433 } 434 for _, val := range cert.PolicyIdentifiers { 435 buf.WriteString(fmt.Sprintf("%16sPolicy: %s\n", "", val.String())) 436 } 437 case 35: 438 // authorityKeyIdentifier: RFC 5280, 4.2.1.1 439 buf.WriteString(fmt.Sprintf("%12sX509v3 Authority Key Identifier:", "")) 440 if ext.Critical { 441 buf.WriteString(" critical\n") 442 } else { 443 buf.WriteString("\n") 444 } 445 //buf.WriteString(fmt.Sprintf("%16skeyid", "")) 446 buf.WriteString(fmt.Sprintf("%16s", "")) 447 for i, val := range cert.AuthorityKeyId { 448 if i == 0 { 449 buf.WriteString(fmt.Sprintf("%02X", val)) 450 } else { 451 buf.WriteString(fmt.Sprintf(":%02X", val)) 452 } 453 454 } 455 buf.WriteString("\n") 456 case 37: 457 // extKeyUsage: RFC 5280, 4.2.1.12 458 buf.WriteString(fmt.Sprintf("%12sX509v3 Extended Key Usage:", "")) 459 if ext.Critical { 460 buf.WriteString(" critical\n") 461 } else { 462 buf.WriteString("\n") 463 } 464 var list []string 465 for _, val := range cert.ExtKeyUsage { 466 switch val { 467 case ExtKeyUsageAny: 468 list = append(list, "Any Usage") 469 case ExtKeyUsageServerAuth: 470 list = append(list, "TLS Web Server Authentication") 471 case ExtKeyUsageClientAuth: 472 list = append(list, "TLS Web Client Authentication") 473 case ExtKeyUsageCodeSigning: 474 list = append(list, "Code Signing") 475 case ExtKeyUsageEmailProtection: 476 list = append(list, "E-mail Protection") 477 case ExtKeyUsageIPSECEndSystem: 478 list = append(list, "IPSec End System") 479 case ExtKeyUsageIPSECTunnel: 480 list = append(list, "IPSec Tunnel") 481 case ExtKeyUsageIPSECUser: 482 list = append(list, "IPSec User") 483 case ExtKeyUsageTimeStamping: 484 list = append(list, "Time Stamping") 485 case ExtKeyUsageOCSPSigning: 486 list = append(list, "OCSP Signing") 487 default: 488 list = append(list, "UNKNOWN") 489 } 490 } 491 if len(list) > 0 { 492 buf.WriteString(fmt.Sprintf("%16s%s", "", list[0])) 493 for i := 1; i < len(list); i++ { 494 buf.WriteString(fmt.Sprintf(", %s", list[i])) 495 } 496 buf.WriteString("\n") 497 } 498 default: 499 buf.WriteString(fmt.Sprintf("Unknown extension 2.5.29.%d\n", ext.Id[3])) 500 } 501 if err != nil { 502 return "", err 503 } 504 } else if ext.Id.Equal(oidExtensionAuthorityInfoAccess) { 505 // authorityInfoAccess: RFC 5280, 4.2.2.1 506 buf.WriteString(fmt.Sprintf("%12sAuthority Information Access:", "")) 507 if ext.Critical { 508 buf.WriteString(" critical\n") 509 } else { 510 buf.WriteString("\n") 511 } 512 if len(cert.OCSPServer) > 0 { 513 buf.WriteString(fmt.Sprintf("%16sOCSP - URI:%s", "", cert.OCSPServer[0])) 514 for i := 1; i < len(cert.OCSPServer); i++ { 515 buf.WriteString(fmt.Sprintf(",URI:%s", cert.OCSPServer[i])) 516 } 517 buf.WriteString("\n") 518 } 519 if len(cert.IssuingCertificateURL) > 0 { 520 buf.WriteString(fmt.Sprintf("%16sCA Issuers - URI:%s", "", cert.IssuingCertificateURL[0])) 521 for i := 1; i < len(cert.IssuingCertificateURL); i++ { 522 buf.WriteString(fmt.Sprintf(",URI:%s", cert.IssuingCertificateURL[i])) 523 } 524 buf.WriteString("\n") 525 } 526 buf.WriteString("\n") 527 } else if ext.Id.Equal(oidNSComment) { 528 // Netscape comment 529 var comment string 530 rest, err := asn1.Unmarshal(ext.Value, &comment) 531 if err != nil || len(rest) > 0 { 532 return "", errors.New("certinfo: Error parsing OID " + ext.Id.String()) 533 } 534 if ext.Critical { 535 buf.WriteString(fmt.Sprintf("%12sNetscape Comment: critical\n%16s%s\n", "", "", comment)) 536 } else { 537 buf.WriteString(fmt.Sprintf("%12sNetscape Comment:\n%16s%s\n", "", "", comment)) 538 } 539 } else if ext.Id.Equal(oidExtensionSignatureAlgorithm) { 540 // SignatureAlgorithm反序列化操作 541 signAlg := SignatureAlgorithm(binary.BigEndian.Uint32(ext.Value)) 542 buf.WriteString(fmt.Sprintf("%12sCustom Extension Signature Algorithm:\n", "")) 543 if signAlg > 0 { 544 buf.WriteString(fmt.Sprintf("%16s%s\n", "", signAlg.String())) 545 } 546 } else { 547 // 输出未知扩展属性 548 buf.WriteString(fmt.Sprintf("%12sUnknown extension %s\n%16s%s\n", "", ext.Id.String(), "", string(ext.Value))) 549 } 550 } 551 buf.WriteString("\n") 552 } 553 554 // Signature 555 printSignature(cert.SignatureAlgorithm, cert.Signature, &buf) 556 557 // Optional: Print the full PEM certificate 558 /* 559 pemBlock := pem.Block{ 560 Type: "CERTIFICATE", 561 Bytes: cert.Raw, 562 } 563 buf.Write(pem.EncodeToMemory(&pemBlock)) 564 */ 565 566 return buf.String(), nil 567 } 568 569 // CertificateRequestText returns a human-readable string representation 570 // of the certificate request csr. The format is similar (but not identical) 571 // to the OpenSSL way of printing certificates. 572 // 573 //goland:noinspection GoUnusedExportedFunction 574 func CertificateRequestText(csr *CertificateRequest) (string, error) { 575 var buf bytes.Buffer 576 buf.Grow(4096) // 4KiB should be enough 577 578 buf.WriteString(fmt.Sprintf("Certificate Request:\n")) 579 buf.WriteString(fmt.Sprintf("%4sData:\n", "")) 580 printVersion(csr.Version, &buf) 581 582 // Subject information 583 err := printSubjectInformation(&csr.Subject, csr.PublicKeyAlgorithm, csr.PublicKey, &buf) 584 if err != nil { 585 return "", err 586 } 587 588 // Optional extensions for X509v3 589 if csr.Version == 3 && len(csr.Extensions) > 0 { 590 buf.WriteString(fmt.Sprintf("%8sRequested Extensions:\n", "")) 591 var err error 592 for _, ext := range csr.Extensions { 593 if len(ext.Id) == 4 && ext.Id[0] == 2 && ext.Id[1] == 5 && ext.Id[2] == 29 { 594 switch ext.Id[3] { 595 case 14: 596 err = printSubjKeyId(ext, &buf) 597 case 17: 598 err = printSubjAltNames(ext, csr.DNSNames, csr.EmailAddresses, csr.IPAddresses, &buf) 599 } 600 } 601 if err != nil { 602 return "", err 603 } 604 } 605 buf.WriteString("\n") 606 } 607 608 // Signature 609 printSignature(csr.SignatureAlgorithm, csr.Signature, &buf) 610 611 return buf.String(), nil 612 }