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  }