Skip to content

Date of Birth incorrectly decoded in UIC/U_FLEX "Deutschlandticket" #51

@prssrp

Description

@prssrp

First off, thank you very much for now providing pre-built wheels - building from source on a virtual machine with only 4GB of bare metal RAM has been a pain in the past...
Using the currently published version "ticket_decoder-0.19-cp314-cp314-manylinux_2_34_x86_64.whl", I experimented a bit with my own "Deutschlandticket" and observed, that my DOB is decoded incorrectly. *censored*-01-10 is decoded instead of the correct *censored*-05-10 (May 10th):

{
	"companyCode": "3634",
	"origin": "D-Ticket_2026-06.pdf",
	"raw": "*censored*",
	"records": {
		"U_FLEX": {
			"issuingDetail": {
				"activated": 1,
				"currency": "EUR",
				"currencyFract": 2,
				"issuerName": "DB Regio AG (Sparte Bus)",
				"issuerNum": 2080,
				"issuerPNR": "D*censored*W",
				"issuingDate": "2026-05-21",
				"issuingTime": "22:24:00",
				"securePaperTicket": 0,
				"securityProviderNum": 3634,
				"specimen": 0
			},
			"transportDocuments": [
				{
					"openTicket": {
						"classCode": "2",
						"extIssuerId": 0,
						"issuerAuthorizationId": 0,
						"price": 0,
						"productIdNum": 9999,
						"reference": "D*censored*W",
						"returnIncluded": 0,
						"stationCodeTable": "0",
						"tariffs": [
							{
								"numberOfPassengers": 1,
								"passengerType": "0",
								"restrictedToCountryOfResidence": 0,
								"tariffDesc": "Deutschlandticket"
							}
						],
						"validFromDate": "2026-06-01",
						"validFromTime": "00:00:00",
						"validUntilDate": "2026-07-01",
						"validUntilTime": "03:00:00"
					}
				}
			],
			"travelerDetail": {
				"traveler": [
					{
						"dateOfBirth": "*censored*-01-10",
						"firstName": "*censored*",
						"gender": "0",
						"lastName": "*censored*",
						"passengerType": "0",
						"ticketHolder": 1
					}
				]
			}
		}
	},
	"signatureKeyId": "DTX04",
	"validated": "false"
}

Using the protraQ Android app, the following results are presented:

Typ: UIC

RAW bytes (279 bytes):
    *censored*

UIC container, id #UT, version 2

RICS Code:    3634 = Deutschlandtarifverbund GmbH
Signature id: DTX04
Signature (71 bytes):
    *censored* 

Compressed message (197 bytes):
    *censored* 

Certificate validation
. Result = Signatur gueltig
. Valid from  = 09.12.2025 12:24:18 Uhr
. Valid until = 08.12.2028 12:24:18 Uhr
. SignatureAlgorithm = SHA256withDSA
. Hint  = 

Decompressed message (189 bytes):
    *censored* 

--------------------------------
Record Id U_FLEX, Version 3
--------------------------------
UicRailTicketData (V3)
. issuingDetail = IssuingData
. . securityProviderNum = 3634
. . issuerNum = 2080
. . issuingYear = 2026
. . issuingDay = 141
. . issuingTime = 1344 = 22:24 Uhr UTC
. . >> issuingDateTime = 22.05.2026 00:24 Uhr CEST
. . issuerName = DB Regio AG (Sparte Bus)
. . specimen = False
. . securePaperTicket = False
. . activated = True
. . currency = EUR
. . currencyFract = 2
. . issuerPNR = D*censored*W
. travelerDetail = TravelerData
. . traveler = Liste (1)
. . . [1] = TravelerType
. . . . firstName = *censored*
. . . . lastName = *censored*
. . . . gender = unspecified
. . . . yearOfBirth = *censored*
. . . . monthOfBirth = 5 = 10.05.*censored*
. . . . dayOfBirth = 10 = 10.05.*censored*
. . . . ticketHolder = True
. . . . passengerType = adult
. transportDocument = Liste (1)
. . [1] = DocumentData
. . . openTicket = OpenTicketData
. . . . referenceIA5 = D*censored*W
. . . . productIdNum = 9999
. . . . extIssuerId = 7008
. . . . issuerAutorizationId = 1141395
. . . . returnIncluded = False
. . . . stationCodeTable = stationUIC
. . . . validRegion = Liste (1)
. . . . . [1] = RegionalValidityType
. . . . . . zones = ZoneType
. . . . . . . stationCodeTable = stationUIC
. . . . validFromDay = 11
. . . . validFromTime = 0 = 00:00 Uhr lokale Zeit
. . . . >> validFromDateTime = 01.06.2026 00:00 Uhr lokale Zeit
. . . . validUntilDay = 30
. . . . validUntilTime = 180 = 03:00 Uhr lokale Zeit
. . . . >> validUntilDateTime = 01.07.2026 03:00 Uhr lokale Zeit
. . . . classCode = second
. . . . tariffs = Liste (1)
. . . . . [1] = TariffType
. . . . . . numberOfPassengers = 1
. . . . . . passengerType = adult
. . . . . . restrictedToCountryOfResidence = False
. . . . . . tariffDesc = Deutschlandticket
. . . . price = 6300
. . . . includedAddOns = Liste (1)
. . . . . [1] = IncludedOpenTicketType
. . . . . . productOwnerIA5 = VDV3000
. . . . . . productIdNum = 9999
. . . . . . externalIssuerId = 7008
. . . . . . issuerAutorizationId = 1141395
. . . . . . stationCodeTable = stationUIC
. . . . . . validRegion = Liste (1)
. . . . . . . [1] = RegionalValidityType
. . . . . . . . zones = ZoneType
. . . . . . . . . carrierIA5 = VDV5000
. . . . . . . . . stationCodeTable = stationUIC
. . . . . . . . . zoneId = Liste (1)
. . . . . . . . . . [1] = 1
. . . . . . . . . binaryZoneId = . . . . . . . . . (leer)
. . . . . . validFromDay = 11
. . . . . . validFromTime = 0 = 00:00 Uhr lokale Zeit
. . . . . . >> validFromDateTime = 01.06.2026 00:00 Uhr lokale Zeit
. . . . . . validUntilDay = 30
. . . . . . validUntilTime = 180 = 03:00 Uhr lokale Zeit
. . . . . . >> validUntilDateTime = 01.07.2026 03:00 Uhr lokale Zeit
. . . . . . classCode = second
. . . . . . carrierIA5 = Liste (1)
. . . . . . . [1] = VDV5000
. controlDetail = ControlData
. . identificationByIdCard = False
. . identificationByPassportId = False
. . passportValidationRequired = False
. . onlineValidationRequired = False
. . ageCheckRequired = False
. . reductionCardCheckRequired = False

System
. App: eu.highq.protraQ 1.3.2
. Device: *censored*
. Lizenz: public
. Zeitpunkt: 29.05.2026 *censored*
. Sperrliste: n/a
. Sperrliste Anzahl Eintraege: 0
. Zertifikate Anzahl Eintraege: VDV 108, UIC 234
. Betriebsbereit: True
. Service Status: [ssBarcodeRegistered, ssNFCRegistered]

Another two points I'd like to remark on:

  1. The publicly downloadable UIC key database at this time has 62 entries when downloaded according to your instructions, VDV_Certificates.ldif contains 44 entries for me when downloaded (via the hint in decoding VDV ticket #43 (comment)), whereas protraQ claims to enumerate a lot more keys: VDV 108, UIC 234.
    I managed to snag DTX04 for my testing directly from a binary in their APK version 1.3.2 (sub-APK config.armeabi_v7a.apk, lib\armeabi-v7a\libprotraQ.so)...
  2. protraQ also prints the correct ticket price (price=6300), whereas your decoder just returns a value of "0". Is that info encoded in the ticket or determined from other source by protraQ?

[edit: redacted issuerPNR]

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions