Skip to content

Support keypair generation for Aliro#2682

Open
HunsupJung wants to merge 3 commits intomainfrom
feature/support-keypair-generation
Open

Support keypair generation for Aliro#2682
HunsupJung wants to merge 3 commits intomainfrom
feature/support-keypair-generation

Conversation

@HunsupJung
Copy link
Collaborator

@HunsupJung HunsupJung commented Jan 2, 2026

Type of Change

  • WWST Certification Request
    • If this is your first time contributing code:
      • I have reviewed the README.md file
      • I have reviewed the CODE_OF_CONDUCT.md file
      • I have signed the CLA
    • I plan on entering a WWST Certification Request or have entered a request through the WWST Certification console at developer.smartthings.com
  • Bug fix
  • New feature
  • Refactor

Checklist

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have verified my changes by testing with a device or have communicated a plan for testing
  • I am adding new behavior, such as adding a sub-driver, and have added and run new unit tests to cover the new behavior

Description of Change

Summary of Completed Tests

@github-actions
Copy link

github-actions bot commented Jan 2, 2026

@github-actions
Copy link

github-actions bot commented Jan 2, 2026

Test Results

   71 files    484 suites   0s ⏱️
2 511 tests 2 510 ✅ 0 💤 1 ❌
4 322 runs  4 321 ✅ 0 💤 1 ❌

For more details on these failures, see this check.

Results for commit 140482b.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Jan 2, 2026

File Coverage
All files 70%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-lock/src/init.lua 92%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-lock/src/lock_utils.lua 98%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-lock/src/new-matter-lock/init.lua 62%

Minimum allowed coverage is 90%

Generated by 🐒 cobertura-action against 140482b

Signed-off-by: Hunsup Jung <hunsup.jung@samsung.com>
@HunsupJung HunsupJung force-pushed the feature/support-keypair-generation branch from ed58efb to 0cf840f Compare January 2, 2026 06:38
@Kwang-Hui
Copy link
Contributor

@tpmanley Could you please review this PR?

}
}
local status = security.generate_self_signed_cert(request_opts)
local privKey = string.sub(utils.bytes_to_hex_string(status.key_der), PRIV_KEY_START, PRIV_KEY_END)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken, this won't always work because it doesn't take into account that DER uses variable length integers. I think we may need to parse the data in order to accurately extract the desired components.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will change it to extract the desired components accurately.

Signed-off-by: Hunsup Jung <hunsup.jung@samsung.com>
Signed-off-by: Hunsup Jung <hunsup.jung@samsung.com>
@HunsupJung HunsupJung force-pushed the feature/support-keypair-generation branch from 3268f4c to 140482b Compare February 5, 2026 02:06

local DoorLock = clusters.DoorLock
local PowerSource = clusters.PowerSource
local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = 0x0101}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = 0x0101}
local DoorLockFeatureMapAttr = {ID = 0xFFFC, cluster = DoorLock.ID}

end
end
end
if device.manufacturer_info.vendor_id == 0x135D then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try to avoid vendor specific checks like this. Any reason we can't just subscribe to the attribute on all devices?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I coded it because I thought @ctowns wanted it to be applied only to specific devices. If I misunderstood, I will delete it.
https://samsung.slack.com/archives/C063J01GHR6/p1765382793593279?thread_ts=1732583132.684279&cid=C063J01GHR6

pos = pos + 2
-- Ignore Version(0x02) and Curve parameters field(0xa0)
if tag == 0x04 then -- Private key field
pubKey = utils.bytes_to_hex_string(string.sub(status.key_der, pos + 1, pos + len))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be privKey?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A and B have changed.

local total_len = string.byte(status.key_der, pos)
local pubKey = nil
local privKey = nil
while pos < total_len + ASN1_TOTAL_LEN_POSITION do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the parsing code is a bit fragile still in that it doesn't handle multi-byte lengths. I haven't tried this code below, but I think it handles the multi-byte lengths and should be more resilient to any changes in the response of generate_self_signed_cert. Could you take a look, maybe test it out and see what you think?

local status = security.generate_self_signed_cert(request_opts)
  if not status or not status.key_der then
    device.log.error("generate_self_signed_cert returned no data")
    return nil, nil
  end

  local der = status.key_der
  local privKey, pubKey = nil, nil

  -- Helper: Parse ASN.1 length (handles 1-byte and multi-byte lengths)
  local function get_length(data, start_pos)
    local b = string.byte(data, start_pos)
    if not b then return nil, start_pos end
    
    if b < 0x80 then
      return b, start_pos + 1
    else
      local num_bytes = b - 0x80
      local len = 0
      for i = 1, num_bytes do
        len = (len * 256) + string.byte(data, start_pos + i)
      end
      return len, start_pos + 1 + num_bytes
    end
  end

  -- Start parsing after the initial SEQUENCE tag (0x30)
  -- Most keys start: [0x30][Length]. We find the first length to find the start of content.
  local _, pos = get_length(der, 2) 

  while pos < #der do
    local tag = string.byte(der, pos)
    local len, content_start = get_length(der, pos + 1)
    if not len then break end

    if tag == 0x02 then 
      -- Version field: Skip it
    elseif tag == 0x04 then 
      -- PRIVATE KEY: Octet String
      privKey = utils.bytes_to_hex_string(string.sub(der, content_start, content_start + len - 1))
    
    elseif tag == 0xA1 then 
      -- PUBLIC KEY Wrapper: Explicit Tag [1]
      -- Inside 0xA1 is a BIT STRING (0x03)
      local inner_tag = string.byte(der, content_start)
      if inner_tag == 0x03 then
        local bit_len, bit_start = get_length(der, content_start + 1)
        
        -- BIT STRINGS have a "leading null byte" (unused bits indicator)
        -- We skip that byte (bit_start) and the 0x04 EC prefix to get the raw X/Y coordinates
        local actual_key_start = bit_start + 2 
        local actual_key_len = bit_len - 2
        
        pubKey = PUB_KEY_PREFIX .. utils.bytes_to_hex_string(string.sub(der, actual_key_start, actual_key_start + actual_key_len - 1))
      end
    end

    -- Move pointer to the next tag
    pos = content_start + len
  end

  if not privKey or not pubKey then
    device.log.error("Failed to extract keys from DER")
  end

  return privKey, pubKey
end

@HunsupJung HunsupJung requested a review from ctowns February 6, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants