qc_statements.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package x509
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "github.com/zmap/zcrypto/encoding/asn1"
  6. )
  7. type QCStatementASN struct {
  8. StatementID asn1.ObjectIdentifier
  9. StatementInfo asn1.RawValue `asn1:"optional"`
  10. }
  11. func (s *QCStatementASN) MarshalJSON() ([]byte, error) {
  12. aux := struct {
  13. ID string `json:"id,omitempty"`
  14. Value []byte `json:"value,omitempty"`
  15. }{
  16. ID: s.StatementID.String(),
  17. Value: s.StatementInfo.Bytes,
  18. }
  19. return json.Marshal(&aux)
  20. }
  21. type QCStatementsASN struct {
  22. QCStatements []QCStatementASN
  23. }
  24. // ETSI OIDS from https://www.etsi.org/deliver/etsi_en/319400_319499/31941205/02.02.03_20/en_31941205v020203a.pdf
  25. var (
  26. oidEtsiQcsQcCompliance = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 1}
  27. oidEtsiQcsQcLimitValue = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 2}
  28. oidEtsiQcsQcRetentionPeriod = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 3}
  29. oidEtsiQcsQcSSCD = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 4}
  30. oidEtsiQcsQcEuPDS = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 5}
  31. oidEtsiQcsQcType = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6}
  32. oidEtsiQcsQcCCLegislation = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 7}
  33. oidEtsiQcsQctEsign = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6, 1}
  34. oidEtsiQcsQctEseal = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6, 2}
  35. oidEtsiQcsQctWeb = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6, 3}
  36. )
  37. type QCStatements struct {
  38. StatementIDs []string `json:"ids,omitempty"`
  39. ParsedStatements *ParsedQCStatements `json:"parsed,omitempty"`
  40. }
  41. type ParsedQCStatements struct {
  42. ETSICompliance []bool `json:"etsi_compliance,omitempty"`
  43. SSCD []bool `json:"sscd,omitempty"`
  44. Types []QCType `json:"types,omitempty"`
  45. Limit []MonetaryValue `json:"limit,omitempty"`
  46. PDSLocations []PDSLocations `json:"pds_locations,omitempty"`
  47. RetentionPeriod []int `json:"retention_period,omitempty"`
  48. Legislation []QCLegistation `json:"legislation,omitempty"`
  49. }
  50. type MonetaryValue struct {
  51. Currency string `json:"currency,omitempty"`
  52. CurrencyNumber int `json:"currency_number,omitempty"`
  53. Amount int `json:"amount,omitempty"`
  54. Exponent int `json:"exponent,omitempty"`
  55. }
  56. type monetaryValueASNString struct {
  57. Currency string `asn1:"printable"`
  58. Amount int
  59. Exponent int
  60. }
  61. type monetaryValueASNNumber struct {
  62. Currency int
  63. Amount int
  64. Exponent int
  65. }
  66. type PDSLocations struct {
  67. Locations []PDSLocation `json:"locations,omitempty"`
  68. }
  69. type PDSLocation struct {
  70. URL string `json:"url,omitempty" asn1:"ia5"`
  71. Language string `json:"language,omitempty" asn1:"printable"`
  72. }
  73. type QCType struct {
  74. TypeIdentifiers []asn1.ObjectIdentifier
  75. }
  76. type QCLegistation struct {
  77. CountryCodes []string `json:"country_codes,omitempty"`
  78. }
  79. func (qt *QCType) MarshalJSON() ([]byte, error) {
  80. aux := struct {
  81. Types []string `json:"ids,omitempty"`
  82. }{
  83. Types: make([]string, len(qt.TypeIdentifiers)),
  84. }
  85. for idx := range qt.TypeIdentifiers {
  86. aux.Types[idx] = qt.TypeIdentifiers[idx].String()
  87. }
  88. return json.Marshal(&aux)
  89. }
  90. func (q *QCStatements) Parse(in *QCStatementsASN) error {
  91. q.StatementIDs = make([]string, len(in.QCStatements))
  92. known := ParsedQCStatements{}
  93. for i, s := range in.QCStatements {
  94. val := in.QCStatements[i].StatementInfo.FullBytes
  95. q.StatementIDs[i] = s.StatementID.String()
  96. if s.StatementID.Equal(oidEtsiQcsQcCompliance) {
  97. known.ETSICompliance = append(known.ETSICompliance, true)
  98. if val != nil {
  99. return errors.New("EtsiQcsQcCompliance QCStatement must not contain a statementInfo")
  100. }
  101. } else if s.StatementID.Equal(oidEtsiQcsQcLimitValue) {
  102. // TODO
  103. mvs := monetaryValueASNString{}
  104. mvn := monetaryValueASNNumber{}
  105. out := MonetaryValue{}
  106. if _, err := asn1.Unmarshal(val, &mvs); err == nil {
  107. out.Currency = mvs.Currency
  108. out.Amount = mvs.Amount
  109. out.Exponent = mvs.Exponent
  110. } else if _, err := asn1.Unmarshal(val, &mvn); err == nil {
  111. out.CurrencyNumber = mvn.Currency
  112. out.Amount = mvn.Amount
  113. out.Exponent = mvn.Exponent
  114. } else {
  115. return err
  116. }
  117. known.Limit = append(known.Limit, out)
  118. } else if s.StatementID.Equal(oidEtsiQcsQcRetentionPeriod) {
  119. var retentionPeriod int
  120. if _, err := asn1.Unmarshal(val, &retentionPeriod); err != nil {
  121. return err
  122. }
  123. known.RetentionPeriod = append(known.RetentionPeriod, retentionPeriod)
  124. } else if s.StatementID.Equal(oidEtsiQcsQcSSCD) {
  125. known.SSCD = append(known.SSCD, true)
  126. if val != nil {
  127. return errors.New("EtsiQcsQcSSCD QCStatement must not contain a statementInfo")
  128. }
  129. } else if s.StatementID.Equal(oidEtsiQcsQcEuPDS) {
  130. locations := make([]PDSLocation, 0)
  131. if _, err := asn1.Unmarshal(val, &locations); err != nil {
  132. return err
  133. }
  134. known.PDSLocations = append(known.PDSLocations, PDSLocations{
  135. Locations: locations,
  136. })
  137. } else if s.StatementID.Equal(oidEtsiQcsQcType) {
  138. typeIds := make([]asn1.ObjectIdentifier, 0)
  139. if _, err := asn1.Unmarshal(val, &typeIds); err != nil {
  140. return err
  141. }
  142. known.Types = append(known.Types, QCType{
  143. TypeIdentifiers: typeIds,
  144. })
  145. } else if s.StatementID.Equal(oidEtsiQcsQcCCLegislation) {
  146. countryCodes := make([]string, 0)
  147. if _, err := asn1.Unmarshal(val, &countryCodes); err != nil {
  148. return err
  149. }
  150. known.Legislation = append(known.Legislation, QCLegistation{
  151. CountryCodes: countryCodes,
  152. })
  153. }
  154. }
  155. q.ParsedStatements = &known
  156. return nil
  157. }