func()

in yubikey/pkg/value/encryption/envelope/piv/manager.go [50:99]


func (o *pivOpener) Open(serial uint32, slot uint8) (Card, error) {
	// Get a retired slot.
	pivSlot, ok := gopiv.RetiredKeyManagementSlot(uint32(slot))
	if !ok {
		return nil, fmt.Errorf("unrecognized slot: %02x", slot)
	}

	// Retrieve all cards
	cards, err := gopiv.Cards()
	if err != nil {
		return nil, fmt.Errorf("cannot list PIV cards: %w", err)
	}

	for _, name := range cards {
		// Try to open card by name
		card, err := o.tryOpen(name, serial)
		if err != nil {
			log.Bg().Debug("ignoring card", zap.Error(err), zap.String("name", name), zap.Uint32("serial", serial))
			continue
		}

		// Retrieve certificate
		cert, err := card.Certificate(pivSlot)
		if err != nil {
			if errors.Is(err, gopiv.ErrNotFound) {
				log.Bg().Debug("ignoring card without certificate", zap.Error(err), zap.String("name", name), zap.Uint32("serial", serial), zap.String("slot", fmt.Sprintf("%02x", slot)))
			} else {
				log.Bg().Debug("communication error", zap.Error(err), zap.String("name", name), zap.Uint32("serial", serial), zap.String("slot", fmt.Sprintf("%02x", slot)))
			}
			continue
		}

		// Filter on required organization
		orgs := cert.Subject.Organization
		if len(orgs) != 1 || orgs[0] != pivOrganization {
			log.Bg().Debug("ignoring card with wrong organization", zap.Error(err), zap.String("name", name), zap.Uint32("serial", serial), zap.String("slot", fmt.Sprintf("%02x", slot)))
			continue
		}

		// Wrap card and return
		return &pivCard{
			card:   card,
			serial: serial,
			slot:   pivSlot,
			pub:    cert.PublicKey.(*ecdsa.PublicKey),
		}, nil
	}

	return nil, errors.New("card not found")
}