func GetMatchingCertsAndChain()

in aws_signing_helper/cert_store_signer_windows.go [149:251]


func GetMatchingCertsAndChain(certIdentifier CertIdentifier) (store windows.Handle, certCtxs []*windows.CertContext, certChains [][]*x509.Certificate, certContainers []CertificateContainer, err error) {
	storeName, err := windows.UTF16PtrFromString(certIdentifier.SystemStoreName)
	if err != nil {
		return 0, nil, nil, nil, errors.New("unable to UTF-16 encode personal certificate store name")
	}

	store, err = windows.CertOpenStore(windows.CERT_STORE_PROV_SYSTEM_W, 0, 0, windows.CERT_SYSTEM_STORE_CURRENT_USER, uintptr(unsafe.Pointer(storeName)))
	if err != nil {
		return 0, nil, nil, nil, errors.New("failed to open system cert store")
	}

	var (
		// CertFindChainInStore parameters
		encoding  = uint32(windows.X509_ASN_ENCODING)
		flags     = uint32(windows.CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG | windows.CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG)
		findType  = uint32(windows.CERT_CHAIN_FIND_BY_ISSUER)
		params    windows.CertChainFindByIssuerPara
		paramsPtr unsafe.Pointer
		chainCtx  *windows.CertChainContext = nil
		certCtx   *windows.CertContext
	)
	params.Size = uint32(unsafe.Sizeof(params))
	paramsPtr = unsafe.Pointer(&params)

	var curCertCtx *windows.CertContext
	var curCert *x509.Certificate
	certContainerIndex := 0
	for {
		// Previous chainCtx should be freed here if it isn't nil
		chainCtx, err = windows.CertFindChainInStore(store, encoding, flags, findType, paramsPtr, chainCtx)
		if err != nil {
			if strings.Contains(err.Error(), "Cannot find object or property.") {
				break
			}
			err = errors.New("unable to find certificate chain in store")
			goto fail
		}

		if chainCtx.ChainCount < 1 {
			err = errors.New("bad chain")
			goto fail
		}

		// When multiple valid certification paths that are found for a given
		// certificate, only the first one is considered
		simpleChain := *chainCtx.Chains
		if simpleChain.NumElements < 1 {
			err = errors.New("bad chain")
			goto fail
		}

		// Convert the array into a pointer
		chainElts := unsafe.Slice(simpleChain.Elements, simpleChain.NumElements)

		// Build chain of certificates from each element's certificate context.
		x509CertChain := make([]*x509.Certificate, len(chainElts))
		for j := range chainElts {
			curCertCtx = chainElts[j].CertContext
			x509CertChain[j], err = exportCertContext(curCertCtx)
			if err != nil {
				if Debug {
					log.Printf("unable to parse certificate with error (%s) - skipping\n", err)
				}
				goto nextIteration
			}
		}

		curCert = x509CertChain[0]
		if certMatches(certIdentifier, *curCert) {
			certContainers = append(certContainers, CertificateContainer{certContainerIndex, curCert, ""})
			certContainerIndex += 1

			certChains = append(certChains, x509CertChain[:])
			certCtx = chainElts[0].CertContext
			// It's the responsibility of the caller to free the below once they are done using it.
			windows.CertDuplicateCertificateContext(certCtx)
			certCtxs = append(certCtxs, certCtx)
		}

	nextIteration:
	}

	if Debug {
		log.Printf("found %d matching identities\n", len(certContainers))
	}

	return store, certCtxs, certChains, certContainers, nil

fail:
	if chainCtx != nil {
		windows.CertFreeCertificateChain(chainCtx)
		chainCtx = nil
	}
	for i, curCertCtx := range certCtxs {
		if curCertCtx != nil {
			windows.CertFreeCertificateContext(curCertCtx)
			certCtxs[i] = nil
		}
	}
	windows.CertCloseStore(store, 0)

	return 0, nil, nil, nil, err
}