func getMatchingCerts()

in aws_signing_helper/pkcs11_signer.go [318:429]


func getMatchingCerts(module *pkcs11.Ctx, slots []SlotIdInfo, uri *pkcs11uri.Pkcs11URI, userPin string, single bool) (matchedSlot SlotIdInfo, session pkcs11.SessionHandle, loggedIn bool, matchingCerts []CertObjInfo, err error) {
	var (
		errNoMatchingCerts error
	)

	errNoMatchingCerts = errors.New("no matching certificates")

	if uri != nil {
		slots = matchSlots(slots, uri)
	}

	// http://david.woodhou.se/draft-woodhouse-cert-best-practice.html#rfc.section.8.1
	//
	// "For locating certificates, applications first iterate over the
	// available tokens without logging in to them. In each token which
	// matches the provided PKCS#11 URI, a search is performed for
	// matching certificate objects."
	for _, slot := range slots {
		curSession, err := module.OpenSession(slot.id, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKS_RO_PUBLIC_SESSION)
		if err != nil {
			if Debug {
				log.Printf("unable to open session in slot %d"+
					" (%s)\n", slot.id, err)
			}
			module.CloseSession(curSession)
			continue
		}

		curMatchingCerts, err := getCertsInSession(module, slot.id, curSession, uri)
		if err == nil && len(curMatchingCerts) > 0 {
			matchingCerts = append(matchingCerts, curMatchingCerts...)
			// We only care about this value when there is a single matching
			// certificate found.
			if matchedSlot == (SlotIdInfo{}) {
				matchedSlot = slot
				session = curSession
				goto skipCloseSession
			}
		}
		module.CloseSession(curSession)
	skipCloseSession:
	}

	if len(matchingCerts) >= 1 {
		goto foundCert
	}

	// http://david.woodhou.se/draft-woodhouse-cert-best-practice.html#rfc.section.8.1
	//
	// "If no match is found, and precisely one token was matched by the
	// specified URI, then the application attempts to log in to that
	// token using a PIN [...]. Another search is performed for matching
	// objects, which this time will return even any certificate objects
	// with the CKA_PRIVATE attribute. Is it important to note that the
	// login should only be attempted if there is precisely one token
	// which matches the URI, and not if there are multiple possible
	// tokens in which the object could reside."
	if len(slots) == 1 {
		if userPin != "" {
			curSession, err := module.OpenSession(slots[0].id, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKS_RO_PUBLIC_SESSION)
			if err != nil {
				err = errNoMatchingCerts
				goto fail
			}

			err = module.Login(curSession, pkcs11.CKU_USER, userPin)
			if err != nil {
				err = errNoMatchingCerts
				goto fail
			}

			curMatchingCerts, err := getCertsInSession(module, slots[0].id, curSession, uri)
			if err == nil && len(curMatchingCerts) > 0 {
				matchingCerts = append(matchingCerts, curMatchingCerts...)
				// We only care about this value when there is a single matching
				// certificate found.
				if session == 0 {
					loggedIn = true
					matchedSlot = slots[0]
					session = curSession
					goto foundCert
				}
			}
		} else {
			err = errors.New("one matching slot, but no user PIN provided")
			goto fail
		}
	} else if len(slots) == 0 {
		err = errors.New("no matching slots")
		goto fail
	} else {
		err = errors.New("multiple matching slots")
		goto fail
	}

foundCert:
	if single && len(matchingCerts) > 1 {
		err = errors.New("multiple matching certificates")
		goto fail
	}

	// Exactly one matching certificate after logging in to the appropriate token
	// iff single is true (otherwise there can be multiple matching certificates).
	return matchedSlot, session, loggedIn, matchingCerts, nil

fail:
	if session != 0 {
		module.Logout(session)
		module.CloseSession(session)
	}
	return SlotIdInfo{}, session, false, nil, err
}