예제 #1
0
        // The list of Keys
        public static void Save(PlaidTemplate instance, string path)
        {
            XmlSerializer x      = new XmlSerializer(typeof(PlaidTemplate));
            TextWriter    writer = new StreamWriter(path);

            x.Serialize(writer, instance);
            writer.Dispose();
        }
예제 #2
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!
        }
예제 #3
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);
        }