Пример #1
0
        /// <summary>
        /// This method performs the full PLAID authentication sequence, given a valid, selected PLAID SAM
        /// and a collection of keysets
        /// </summary>
        /// <param name="sam">The instance of a PLAID SAM</param>
        /// <param name="keysets">The collection of keyset identifiers to request</param>
        /// <param name="opMode">The requested opMode</param>
        /// <returns>The ACSRecord associated with the requested OpMode</returns>
        public byte[] Authenticate(IPlaidSAM sam, KeysetList keysets, short samId, short opMode)
        {
            // Initial Authenticate
#if PLAIDEXPLICITSELECT
            SelectApplication();
#endif
            byte[] estr1 = InitialAuthenticate(keysets);
#if PLAIDEXPLICITSELECT
            sam.SelectApplication(); // REMOVE
#endif
            byte[] estr2 = sam.InitialAuthenticate(samId, estr1, opMode);

            // Final Authenticate
#if PLAIDEXPLICITSELECT
            SelectApplication();
#endif
            byte[] estr3 = FinalAuthenticate(estr2);
#if PLAIDEXPLICITSELECT
            sam.SelectApplication(); // REMOVE
#endif

            return(sam.FinalAuthenticate(estr3));
        }
Пример #2
0
        public bool Verify(IPlaidSAM sam, PlaidTemplate template, Dictionary <string, byte[]> parameters = null)
        {
            SelectApplication();

            bool result = true;

            // Validate the PLAID applet status is STATE_SELECTABLE
            var status = GetStatus();

            // Validate our personalisation status, depending on whether the template automatically blocks the applet
            if (template.Blocked)
            {
                if (status.AppletState == PlaidAppletState.Blocked)
                {
                    RaiseOnMessage(@"PASS: Applet state is set to Blocked");
                }
                else
                {
                    RaiseOnMessage(@"FAIL: Applet state is not set to Blocked");
                    result = false;
                }
            }
            else
            {
                if (status.AppletState == PlaidAppletState.Personalised)
                {
                    RaiseOnMessage(@"PASS: Applet state is set to Personalised");
                }
                else
                {
                    RaiseOnMessage(@"FAIL: Applet state is not set to Personalised");
                    result = false;
                }
            }


            // Load all Keysets in descending order so that KEYSET_ADMIN is last
            foreach (var keyset in template.Keysets.OrderByDescending(x => x.Id))
            {
                if (template.Blocked && keyset.Id != KEYSET_ADMIN)
                {
                    RaiseOnMessage(@"SKIP: Authenticate keyset '" + keyset.IdBytes.ToHexString() + "' (application blocked)");
                    continue;
                }

                try
                {
                    Authenticate(sam, keyset.Id, keyset.SamId, 0);
                    RaiseOnMessage(@"PASS: Authenticate keyset '" + keyset.IdBytes.ToHexString() + "'");
                }
                catch (Exception)
                {
                    RaiseOnMessage(@"FAIL: Authenticate keyset '" + keyset.IdBytes.ToHexString() + "'");
                    result = false;
                }
            }

            // Verify all ACSRecords
            foreach (var record in template.ACSRecords)
            {
                // Determine the actual data
                byte[] expectedData;
                if (record.IsTemplate())
                {
                    expectedData = parameters[record.Data];
                }
                else
                {
                    expectedData = record.DataToArray();
                }

                // Retrieve the ACSRecord with the KEYSET_ADMIN keyset so we know we can always have permission to read it
                var    keyset     = template.Keysets.First(k => k.Id == KEYSET_ADMIN);
                byte[] actualData = Authenticate(sam, keyset.Id, keyset.SamId, record.OpModeId);

                // Compare the byte arrays
                if (expectedData.SequenceEqual(actualData))
                {
                    RaiseOnMessage(@"PASS: Retrieve ACSRecord '" + record.OpModeIdBytes.ToHexString() + "' (" + actualData.ToHexString() + ")");
                }
                else
                {
                    RaiseOnMessage(@"FAIL: Retrieve ACSRecord '" + record.OpModeIdBytes.ToHexString() + "' (expected '" + expectedData.ToHexString() + "' but got '" + actualData.ToHexString() + "')");
                    result = false;
                }
            }

            // Done!
            return(result);
        }
Пример #3
0
        public void Personalise(IPlaidSAM sam, PlaidTemplate template, Dictionary <string, byte[]> parameters = null)
        {
            SelectApplication();

            // Validate the PLAID applet status is STATE_SELECTABLE
            var status = GetStatus();

            if (status.AppletState != PlaidAppletState.Selectable)
            {
                RaiseOnMessage(@"PLAID: Already personalised (performing factory reset)");
                // During debugging, perform a factory reset
                if (status.AppletState == PlaidAppletState.Terminated)
                {
                    throw new ApplicationException(@"Invalid applet state for factory reset");
                }

                // Authenticate using the administrative key
                var adminKeyset = template.Keysets.First(x => x.Id == PlaidApplication.KEYSET_ADMIN);
                Authenticate(sam, adminKeyset.Id, adminKeyset.SamId, 0);

                // Perform a FACTORY_RESET command
                {
                    var request = new FactoryResetRequest();

#if PLAIDEXPLICITSELECT
                    sam.SelectApplication();
#endif
                    byte[] cryptogram = sam.SetData(request.Encode());

#if PLAIDEXPLICITSELECT
                    SelectApplication();
#endif
                    SetData(cryptogram);
                }
            }

            // Retrieve and load the FA KEY cryptogram
            RaiseOnMessage(@"PLAID: Retrieving transport cryptogram");
            byte[] faKey = GetData(0x00);
#if PLAIDEXPLICITSELECT
            sam.SelectApplication();
#endif
            sam.LoadFAKey(template.TransportKey.SamId, faKey);

            // Authenticate using the TransportKey key
            // NOTE: We don't care which OpMode we request since this is an administrative authentication
            RaiseOnMessage(@"PLAID: Authenticating with transport admin keyset");
            byte[] acsRecord = Authenticate(sam, template.TransportKey.Id, template.TransportKey.SamId, 0);

            // Load all ACSRecords
            foreach (var record in template.ACSRecords)
            {
                // Create the request object
                var request = new AcsrCreateRequest();
                request.Id = record.OpModeId;

                if (record.IsTemplate())
                {
                    request.Data = parameters[record.Data];
                }
                else
                {
                    request.Data = record.DataToArray();
                }

                RaiseOnMessage($"PLAID: Writing ACSRecord {request.Id} ({request.Data.ToHexString()})");

                // Generate the cryptogram
#if PLAIDEXPLICITSELECT
                sam.SelectApplication();
#endif
                byte[] cryptogram = sam.SetData(request.Encode());

                // Transmit to the ICC
#if PLAIDEXPLICITSELECT
                SelectApplication();
#endif
                SetData(cryptogram);
            }

            // Load all Keysets in descending order so that KEYSET_ADMIN is last
            foreach (var keyset in template.Keysets.OrderByDescending(x => x.Id))
            {
                // Create the request object
                var request = new KeyCreateRequest();

                request.Id    = keyset.Id;
                request.SamId = keyset.SamId;

                foreach (var rule in keyset.AccessRules)
                {
                    request.Rules.Add(rule);
                }

                // Generate the cryptogram
#if PLAIDEXPLICITSELECT
                sam.SelectApplication();
#endif
                RaiseOnMessage($"PLAID: Loading keyset {keyset.Id:X4}");
                byte[] cryptogram = sam.SetData(request.Encode());

                // Transmit to the ICC
#if PLAIDEXPLICITSELECT
                SelectApplication();
#endif
                SetData(cryptogram);
            }

            // Re-authenticate with the Administrative key
            // NOTE: We don't care which OpMode we request since this is an administrative authentication
            RaiseOnMessage(@"PLAID: Authenticating with admin keyset");
            Authenticate(sam, template.AdminKey.Id, template.AdminKey.SamId, 0);

            // Activate the instance
            {
                RaiseOnMessage(@"PLAID: Updating applet state to PERSONALISED");
                var request = new ActivateRequest();

#if PLAIDEXPLICITSELECT
                sam.SelectApplication();
#endif
                byte[] cryptogram = sam.SetData(request.Encode());

#if PLAIDEXPLICITSELECT
                SelectApplication();
#endif
                SetData(cryptogram);
            }

            // If required, Block the instance
            if (template.Blocked)
            {
                RaiseOnMessage(@"PLAID: Updating applet state to BLOCKED");
                var request = new BlockRequest();

#if PLAIDEXPLICITSELECT
                sam.SelectApplication();
#endif
                byte[] cryptogram = sam.SetData(request.Encode());

#if PLAIDEXPLICITSELECT
                SelectApplication();
#endif
                SetData(cryptogram);
            }

            // Done!
        }
Пример #4
0
 /// <summary>
 /// This method performs the full PLAID authentication sequence, given a valid, selected PLAID SAM
 /// and a single keyset
 /// </summary>
 /// <param name="sam">The instance of a PLAID SAM</param>
 /// <param name="keyset">The single keyset identifier to request</param>
 /// <param name="opMode">The requested opMode</param>
 /// <returns>The ACSRecord associated with the requested OpMode</returns>
 public byte[] Authenticate(IPlaidSAM sam, short keysetId, short samId, short opMode)
 {
     return(Authenticate(sam, new KeysetList(keysetId), samId, opMode));
 }